• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // WebGLCompatibilityTest.cpp : Tests of the GL_ANGLE_webgl_compatibility extension.
8 
9 #include "test_utils/ANGLETest.h"
10 
11 #include "common/mathutil.h"
12 #include "test_utils/gl_raii.h"
13 
14 namespace
15 {
16 
ConstantColorAndAlphaBlendFunctions(GLenum first,GLenum second)17 bool ConstantColorAndAlphaBlendFunctions(GLenum first, GLenum second)
18 {
19     return (first == GL_CONSTANT_COLOR || first == GL_ONE_MINUS_CONSTANT_COLOR) &&
20            (second == GL_CONSTANT_ALPHA || second == GL_ONE_MINUS_CONSTANT_ALPHA);
21 }
22 
CheckBlendFunctions(GLenum src,GLenum dst)23 void CheckBlendFunctions(GLenum src, GLenum dst)
24 {
25     if (ConstantColorAndAlphaBlendFunctions(src, dst) ||
26         ConstantColorAndAlphaBlendFunctions(dst, src))
27     {
28         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
29     }
30     else
31     {
32         ASSERT_GL_NO_ERROR();
33     }
34 }
35 
36 // Extensions that affect the ability to use floating point textures
37 constexpr const char *FloatingPointTextureExtensions[] = {
38     "",
39     "GL_EXT_texture_storage",
40     "GL_OES_texture_half_float",
41     "GL_OES_texture_half_float_linear",
42     "GL_EXT_color_buffer_half_float",
43     "GL_OES_texture_float",
44     "GL_OES_texture_float_linear",
45     "GL_EXT_color_buffer_float",
46     "GL_EXT_float_blend",
47     "GL_CHROMIUM_color_buffer_float_rgba",
48     "GL_CHROMIUM_color_buffer_float_rgb",
49 };
50 
51 }  // namespace
52 
53 namespace angle
54 {
55 
56 class WebGLCompatibilityTest : public ANGLETest<>
57 {
58   protected:
WebGLCompatibilityTest()59     WebGLCompatibilityTest()
60     {
61         setWindowWidth(128);
62         setWindowHeight(128);
63         setConfigRedBits(8);
64         setConfigGreenBits(8);
65         setConfigBlueBits(8);
66         setConfigAlphaBits(8);
67         setWebGLCompatibilityEnabled(true);
68     }
69 
70     template <typename T>
TestFloatTextureFormat(GLenum internalFormat,GLenum format,GLenum type,bool texturingEnabled,bool linearSamplingEnabled,bool renderingEnabled,const T textureData[4],const float floatData[4])71     void TestFloatTextureFormat(GLenum internalFormat,
72                                 GLenum format,
73                                 GLenum type,
74                                 bool texturingEnabled,
75                                 bool linearSamplingEnabled,
76                                 bool renderingEnabled,
77                                 const T textureData[4],
78                                 const float floatData[4])
79     {
80         ASSERT_GL_NO_ERROR();
81 
82         constexpr char kVS[] =
83             R"(attribute vec4 position;
84 varying vec2 texcoord;
85 void main()
86 {
87     gl_Position = vec4(position.xy, 0.0, 1.0);
88     texcoord = (position.xy * 0.5) + 0.5;
89 })";
90 
91         constexpr char kFS[] =
92             R"(precision mediump float;
93 uniform sampler2D tex;
94 uniform vec4 subtractor;
95 varying vec2 texcoord;
96 void main()
97 {
98     vec4 color = texture2D(tex, texcoord);
99     if (abs(color.r - subtractor.r) +
100         abs(color.g - subtractor.g) +
101         abs(color.b - subtractor.b) +
102         abs(color.a - subtractor.a) < 8.0)
103     {
104         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
105     }
106     else
107     {
108         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
109     }
110 })";
111 
112         ANGLE_GL_PROGRAM(samplingProgram, kVS, kFS);
113         glUseProgram(samplingProgram);
114 
115         // Need RGBA8 renderbuffers for enough precision on the readback
116         if (IsGLExtensionRequestable("GL_OES_rgb8_rgba8"))
117         {
118             glRequestExtensionANGLE("GL_OES_rgb8_rgba8");
119         }
120         ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") &&
121                            getClientMajorVersion() < 3);
122         ASSERT_GL_NO_ERROR();
123 
124         GLRenderbuffer rbo;
125         glBindRenderbuffer(GL_RENDERBUFFER, rbo);
126         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
127 
128         GLFramebuffer fbo;
129         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
130         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
131 
132         GLTexture texture;
133         glBindTexture(GL_TEXTURE_2D, texture);
134 
135         if (internalFormat == format)
136         {
137             glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, textureData);
138         }
139         else
140         {
141             if (getClientMajorVersion() >= 3)
142             {
143                 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
144             }
145             else
146             {
147                 ASSERT_TRUE(IsGLExtensionEnabled("GL_EXT_texture_storage"));
148                 glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
149             }
150             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, format, type, textureData);
151         }
152 
153         if (!texturingEnabled)
154         {
155             // Depending on the entry point and client version, different errors may be generated
156             ASSERT_GLENUM_NE(GL_NO_ERROR, glGetError());
157 
158             // Two errors may be generated in the glTexStorage + glTexSubImage case, clear the
159             // second error
160             glGetError();
161 
162             return;
163         }
164         ASSERT_GL_NO_ERROR();
165 
166         glUniform1i(glGetUniformLocation(samplingProgram, "tex"), 0);
167         glUniform4fv(glGetUniformLocation(samplingProgram, "subtractor"), 1, floatData);
168 
169         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
170         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
171         drawQuad(samplingProgram, "position", 0.5f, 1.0f, true);
172         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
173 
174         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
175         drawQuad(samplingProgram, "position", 0.5f, 1.0f, true);
176 
177         if (linearSamplingEnabled)
178         {
179             EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
180         }
181         else
182         {
183             EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
184         }
185 
186         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
187         glBindTexture(GL_TEXTURE_2D, 0);
188         if (!renderingEnabled)
189         {
190             EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
191                              glCheckFramebufferStatus(GL_FRAMEBUFFER));
192             return;
193         }
194 
195         GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
196         if (framebufferStatus == GL_FRAMEBUFFER_UNSUPPORTED)
197         {
198             std::cout << "Framebuffer returned GL_FRAMEBUFFER_UNSUPPORTED, this is legal."
199                       << std::endl;
200             return;
201         }
202         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, framebufferStatus);
203 
204         ANGLE_GL_PROGRAM(renderingProgram, essl1_shaders::vs::Simple(),
205                          essl1_shaders::fs::UniformColor());
206         glUseProgram(renderingProgram);
207 
208         glUniform4fv(glGetUniformLocation(renderingProgram, essl1_shaders::ColorUniform()), 1,
209                      floatData);
210 
211         drawQuad(renderingProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
212 
213         EXPECT_PIXEL_COLOR32F_NEAR(
214             0, 0, GLColor32F(floatData[0], floatData[1], floatData[2], floatData[3]), 1.0f);
215     }
216 
TestExtFloatBlend(GLenum internalFormat,GLenum type,bool shouldBlend)217     void TestExtFloatBlend(GLenum internalFormat, GLenum type, bool shouldBlend)
218     {
219         constexpr char kVS[] =
220             R"(void main()
221 {
222     gl_PointSize = 1.0;
223     gl_Position = vec4(0, 0, 0, 1);
224 })";
225 
226         constexpr char kFS[] =
227             R"(void main()
228 {
229     gl_FragColor = vec4(0.5, 0, 0, 0);
230 })";
231 
232         ANGLE_GL_PROGRAM(program, kVS, kFS);
233         glUseProgram(program);
234 
235         GLTexture texture;
236         glBindTexture(GL_TEXTURE_2D, texture);
237         glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, type, nullptr);
238         EXPECT_GL_NO_ERROR();
239 
240         GLFramebuffer fbo;
241         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
242         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
243         ASSERT_EGLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
244 
245         glClearColor(1, 0, 1, 1);
246         glClear(GL_COLOR_BUFFER_BIT);
247         EXPECT_PIXEL_COLOR32F_NEAR(0, 0, GLColor32F(1, 0, 1, 1), 0.001f);
248 
249         glDisable(GL_BLEND);
250         glDrawArrays(GL_POINTS, 0, 1);
251         EXPECT_GL_NO_ERROR();
252 
253         glEnable(GL_BLEND);
254         glBlendFunc(GL_CONSTANT_COLOR, GL_ZERO);
255         glBlendColor(10, 1, 1, 1);
256         glViewport(0, 0, 1, 1);
257         glDrawArrays(GL_POINTS, 0, 1);
258         if (!shouldBlend)
259         {
260             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
261             return;
262         }
263         EXPECT_GL_NO_ERROR();
264 
265         // Ensure that the stored value reflect the actual platform behavior.
266         float storedColor[4];
267         glGetFloatv(GL_BLEND_COLOR, storedColor);
268         if (storedColor[0] == 10)
269         {
270             EXPECT_PIXEL_COLOR32F_NEAR(0, 0, GLColor32F(5, 0, 0, 0), 0.001f);
271         }
272         else
273         {
274             EXPECT_PIXEL_COLOR32F_NEAR(0, 0, GLColor32F(0.5, 0, 0, 0), 0.001f);
275         }
276 
277         // Check sure that non-float attachments clamp BLEND_COLOR.
278         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
279         glDrawArrays(GL_POINTS, 0, 1);
280 
281         EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0x80, 0, 0, 0), 1);
282     }
283 
284     void TestDifferentStencilMaskAndRef(GLenum errIfMismatch);
285 
286     // Called from RenderingFeedbackLoopWithDrawBuffersEXT.
287     void drawBuffersEXTFeedbackLoop(GLuint program,
288                                     const std::array<GLenum, 2> &drawBuffers,
289                                     GLenum expectedError);
290 
291     // Called from RenderingFeedbackLoopWithDrawBuffers.
292     void drawBuffersFeedbackLoop(GLuint program,
293                                  const std::array<GLenum, 2> &drawBuffers,
294                                  GLenum expectedError);
295 
296     // Called from Enable[Compressed]TextureFormatExtensions
297     void validateTexImageExtensionFormat(GLenum format, const std::string &extName);
298     void validateCompressedTexImageExtensionFormat(GLenum format,
299                                                    GLsizei width,
300                                                    GLsizei height,
301                                                    GLsizei blockSize,
302                                                    const std::string &extName,
303                                                    bool subImageAllowed);
304 
305     GLint expectedByteLength(GLenum format, GLsizei width, GLsizei height);
306     void testCompressedTexLevelDimension(GLenum format,
307                                          GLint level,
308                                          GLsizei width,
309                                          GLsizei height,
310                                          GLsizei expectedByteLength,
311                                          GLenum expectedError,
312                                          const char *explanation);
313     void testCompressedTexImage(GLenum format);
314 };
315 
316 class WebGL2CompatibilityTest : public WebGLCompatibilityTest
317 {};
318 
319 // Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
320 // the GL extension should always be present
TEST_P(WebGLCompatibilityTest,ExtensionStringExposed)321 TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
322 {
323     EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_webgl_compatibility"));
324 }
325 
326 // Verify that all extension entry points are available
TEST_P(WebGLCompatibilityTest,EntryPoints)327 TEST_P(WebGLCompatibilityTest, EntryPoints)
328 {
329     if (IsGLExtensionEnabled("GL_ANGLE_request_extension"))
330     {
331         EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
332     }
333 }
334 
335 // WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point.  Make sure it is usable,
336 // even in ES2 contexts.
TEST_P(WebGLCompatibilityTest,DepthStencilBindingPoint)337 TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
338 {
339     GLRenderbuffer renderbuffer;
340     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
341     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
342 
343     GLFramebuffer framebuffer;
344     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
345     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
346                               renderbuffer);
347 
348     EXPECT_GL_NO_ERROR();
349 }
350 
351 // Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
TEST_P(WebGLCompatibilityTest,EnableExtensionValidation)352 TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
353 {
354     glRequestExtensionANGLE("invalid_extension_string");
355     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
356 }
357 
358 // Test enabling the GL_OES_element_index_uint extension
TEST_P(WebGLCompatibilityTest,EnableExtensionUintIndices)359 TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
360 {
361     if (getClientMajorVersion() != 2)
362     {
363         // This test only works on ES2 where uint indices are not available by default
364         return;
365     }
366 
367     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_element_index_uint"));
368 
369     GLBuffer indexBuffer;
370     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
371 
372     GLuint data[] = {0, 1, 2, 1, 3, 2};
373     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
374 
375     ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
376                      "void main() { gl_FragColor = vec4(0, 1, 0, 1); }");
377     glUseProgram(program);
378 
379     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
380     EXPECT_GL_ERROR(GL_INVALID_ENUM);
381 
382     if (IsGLExtensionRequestable("GL_OES_element_index_uint"))
383     {
384         glRequestExtensionANGLE("GL_OES_element_index_uint");
385         EXPECT_GL_NO_ERROR();
386         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_element_index_uint"));
387 
388         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
389         EXPECT_GL_NO_ERROR();
390     }
391 }
392 
393 // Test enabling the GL_OES_standard_derivatives extension
TEST_P(WebGLCompatibilityTest,EnableExtensionStandardDerivitives)394 TEST_P(WebGLCompatibilityTest, EnableExtensionStandardDerivitives)
395 {
396     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_standard_derivatives"));
397 
398     constexpr char kFS[] =
399         R"(#extension GL_OES_standard_derivatives : require
400 void main() { gl_FragColor = vec4(dFdx(vec2(1.0, 1.0)).x, 1, 0, 1); })";
401     ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFS));
402 
403     if (IsGLExtensionRequestable("GL_OES_standard_derivatives"))
404     {
405         glRequestExtensionANGLE("GL_OES_standard_derivatives");
406         EXPECT_GL_NO_ERROR();
407         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_standard_derivatives"));
408 
409         GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
410         ASSERT_NE(0u, shader);
411         glDeleteShader(shader);
412     }
413 }
414 
415 // Test enabling the GL_EXT_shader_texture_lod extension
TEST_P(WebGLCompatibilityTest,EnableExtensionTextureLOD)416 TEST_P(WebGLCompatibilityTest, EnableExtensionTextureLOD)
417 {
418     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_shader_texture_lod"));
419 
420     constexpr char kFS[] =
421         R"(#extension GL_EXT_shader_texture_lod : require
422 uniform sampler2D u_texture;
423 void main() {
424     gl_FragColor = texture2DGradEXT(u_texture, vec2(0.0, 0.0), vec2(0.0, 0.0), vec2(0.0,
425 0.0));
426 })";
427     ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFS));
428 
429     if (IsGLExtensionRequestable("GL_EXT_shader_texture_lod"))
430     {
431         glRequestExtensionANGLE("GL_EXT_shader_texture_lod");
432         EXPECT_GL_NO_ERROR();
433         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_shader_texture_lod"));
434 
435         GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
436         ASSERT_NE(0u, shader);
437         glDeleteShader(shader);
438     }
439 }
440 
441 // Test enabling the GL_EXT_frag_depth extension
TEST_P(WebGLCompatibilityTest,EnableExtensionFragDepth)442 TEST_P(WebGLCompatibilityTest, EnableExtensionFragDepth)
443 {
444     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_frag_depth"));
445 
446     constexpr char kFS[] =
447         R"(#extension GL_EXT_frag_depth : require
448 void main() {
449     gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
450     gl_FragDepthEXT = 1.0;
451 })";
452     ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFS));
453 
454     if (IsGLExtensionRequestable("GL_EXT_frag_depth"))
455     {
456         glRequestExtensionANGLE("GL_EXT_frag_depth");
457         EXPECT_GL_NO_ERROR();
458         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_frag_depth"));
459 
460         GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
461         ASSERT_NE(0u, shader);
462         glDeleteShader(shader);
463     }
464 }
465 
466 // Test enabling the GL_EXT_texture_filter_anisotropic extension
TEST_P(WebGLCompatibilityTest,EnableExtensionTextureFilterAnisotropic)467 TEST_P(WebGLCompatibilityTest, EnableExtensionTextureFilterAnisotropic)
468 {
469     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_texture_filter_anisotropic"));
470 
471     GLfloat maxAnisotropy = 0.0f;
472     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
473     EXPECT_GL_ERROR(GL_INVALID_ENUM);
474 
475     GLTexture texture;
476     glBindTexture(GL_TEXTURE_2D, texture);
477     ASSERT_GL_NO_ERROR();
478 
479     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
480     EXPECT_GL_ERROR(GL_INVALID_ENUM);
481 
482     GLfloat currentAnisotropy = 0.0f;
483     glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
484     EXPECT_GL_ERROR(GL_INVALID_ENUM);
485 
486     if (IsGLExtensionRequestable("GL_EXT_texture_filter_anisotropic"))
487     {
488         glRequestExtensionANGLE("GL_EXT_texture_filter_anisotropic");
489         EXPECT_GL_NO_ERROR();
490         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_texture_filter_anisotropic"));
491 
492         glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
493         ASSERT_GL_NO_ERROR();
494         EXPECT_GE(maxAnisotropy, 2.0f);
495 
496         glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
497         ASSERT_GL_NO_ERROR();
498         EXPECT_EQ(1.0f, currentAnisotropy);
499 
500         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f);
501         ASSERT_GL_NO_ERROR();
502     }
503 }
504 
505 // Test enabling the EGL image extensions
TEST_P(WebGLCompatibilityTest,EnableExtensionEGLImage)506 TEST_P(WebGLCompatibilityTest, EnableExtensionEGLImage)
507 {
508     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_EGL_image"));
509     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_EGL_image_external"));
510     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_EGL_image_external_essl3"));
511     EXPECT_FALSE(IsGLExtensionEnabled("NV_EGL_stream_consumer_external"));
512 
513     constexpr char kFSES2[] =
514         R"(#extension GL_OES_EGL_image_external : require
515 precision highp float;
516 uniform samplerExternalOES sampler;
517 void main()
518 {
519     gl_FragColor = texture2D(sampler, vec2(0, 0));
520 })";
521     EXPECT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES2));
522 
523     constexpr char kFSES3[] =
524         R"(#version 300 es
525 #extension GL_OES_EGL_image_external_essl3 : require
526 precision highp float;
527 uniform samplerExternalOES sampler;
528 out vec4 my_FragColor;
529 void main()
530 {
531     my_FragColor = texture(sampler, vec2(0, 0));
532 })";
533     if (getClientMajorVersion() >= 3)
534     {
535         EXPECT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES3));
536     }
537 
538     glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
539     EXPECT_GL_ERROR(GL_INVALID_ENUM);
540 
541     GLint result;
542     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &result);
543     EXPECT_GL_ERROR(GL_INVALID_ENUM);
544 
545     if (IsGLExtensionRequestable("GL_OES_EGL_image_external"))
546     {
547         glRequestExtensionANGLE("GL_OES_EGL_image_external");
548         EXPECT_GL_NO_ERROR();
549         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external"));
550 
551         EXPECT_NE(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES2));
552 
553         glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
554         EXPECT_GL_NO_ERROR();
555 
556         glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &result);
557         EXPECT_GL_NO_ERROR();
558 
559         if (getClientMajorVersion() >= 3 &&
560             IsGLExtensionRequestable("GL_OES_EGL_image_external_essl3"))
561         {
562             glRequestExtensionANGLE("GL_OES_EGL_image_external_essl3");
563             EXPECT_GL_NO_ERROR();
564             EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external_essl3"));
565 
566             EXPECT_NE(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES3));
567         }
568         else
569         {
570             EXPECT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES3));
571         }
572     }
573 }
574 
575 // Verify that shaders are of a compatible spec when the extension is enabled.
TEST_P(WebGLCompatibilityTest,ExtensionCompilerSpec)576 TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
577 {
578     EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_webgl_compatibility"));
579 
580     // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
581     constexpr char kVS[] =
582         R"(struct Foo {
583     int _webgl_bar;
584 };
585 void main()
586 {
587     Foo foo = Foo(1);
588 })";
589 
590     // Default fragement shader.
591     constexpr char kFS[] =
592         R"(void main()
593 {
594     gl_FragColor = vec4(1.0,0.0,0.0,1.0);
595 })";
596 
597     GLuint program = CompileProgram(kVS, kFS);
598     EXPECT_EQ(0u, program);
599     glDeleteProgram(program);
600 }
601 
602 // Test enabling the GL_NV_pixel_buffer_object extension
TEST_P(WebGLCompatibilityTest,EnablePixelBufferObjectExtensions)603 TEST_P(WebGLCompatibilityTest, EnablePixelBufferObjectExtensions)
604 {
605     EXPECT_FALSE(IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
606     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_mapbuffer"));
607     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_map_buffer_range"));
608 
609     // These extensions become core in in ES3/WebGL2.
610     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
611 
612     // http://anglebug.com/40644771
613     ANGLE_SKIP_TEST_IF(IsMac() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
614 
615     GLBuffer buffer;
616     glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
617     EXPECT_GL_ERROR(GL_INVALID_ENUM);
618 
619     if (IsGLExtensionRequestable("GL_NV_pixel_buffer_object"))
620     {
621         glRequestExtensionANGLE("GL_NV_pixel_buffer_object");
622         EXPECT_GL_NO_ERROR();
623 
624         // Create a framebuffer to read from
625         GLRenderbuffer renderbuffer;
626         glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
627         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
628 
629         GLFramebuffer fbo;
630         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
631         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
632                                   renderbuffer);
633         EXPECT_GL_NO_ERROR();
634 
635         glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
636         EXPECT_GL_NO_ERROR();
637 
638         glBufferData(GL_PIXEL_PACK_BUFFER, 4, nullptr, GL_STATIC_DRAW);
639         glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
640         EXPECT_GL_NO_ERROR();
641     }
642 }
643 
644 // Test enabling the GL_EXT_texture_storage extension
TEST_P(WebGLCompatibilityTest,EnableTextureStorage)645 TEST_P(WebGLCompatibilityTest, EnableTextureStorage)
646 {
647     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_texture_storage"));
648 
649     GLTexture texture;
650     glBindTexture(GL_TEXTURE_2D, texture);
651 
652     GLint result;
653     glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &result);
654     if (getClientMajorVersion() >= 3)
655     {
656         EXPECT_GL_NO_ERROR();
657     }
658     else
659     {
660         EXPECT_GL_ERROR(GL_INVALID_ENUM);
661     }
662 
663     if (IsGLExtensionRequestable("GL_EXT_texture_storage"))
664     {
665         glRequestExtensionANGLE("GL_EXT_texture_storage");
666         EXPECT_GL_NO_ERROR();
667         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_texture_storage"));
668 
669         glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &result);
670         EXPECT_GL_NO_ERROR();
671 
672         const GLenum alwaysAcceptableFormats[] = {
673             GL_ALPHA8_EXT,
674             GL_LUMINANCE8_EXT,
675             GL_LUMINANCE8_ALPHA8_EXT,
676         };
677         for (const auto &acceptableFormat : alwaysAcceptableFormats)
678         {
679             GLTexture localTexture;
680             glBindTexture(GL_TEXTURE_2D, localTexture);
681             glTexStorage2DEXT(GL_TEXTURE_2D, 1, acceptableFormat, 1, 1);
682             EXPECT_GL_NO_ERROR();
683         }
684     }
685 }
686 
687 // Test enabling the GL_OES_mapbuffer and GL_EXT_map_buffer_range extensions
TEST_P(WebGLCompatibilityTest,EnableMapBufferExtensions)688 TEST_P(WebGLCompatibilityTest, EnableMapBufferExtensions)
689 {
690     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_mapbuffer"));
691     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_map_buffer_range"));
692 
693     // These extensions become core in in ES3/WebGL2.
694     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
695 
696     GLBuffer buffer;
697     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
698     glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4, nullptr, GL_STATIC_DRAW);
699 
700     glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
701     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
702 
703     glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
704     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
705 
706     GLint access = 0;
707     glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
708     EXPECT_GL_ERROR(GL_INVALID_ENUM);
709 
710     if (IsGLExtensionRequestable("GL_OES_mapbuffer"))
711     {
712         glRequestExtensionANGLE("GL_OES_mapbuffer");
713         EXPECT_GL_NO_ERROR();
714 
715         glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
716         glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
717         glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
718         EXPECT_GL_NO_ERROR();
719     }
720 
721     if (IsGLExtensionRequestable("GL_EXT_map_buffer_range"))
722     {
723         glRequestExtensionANGLE("GL_EXT_map_buffer_range");
724         EXPECT_GL_NO_ERROR();
725 
726         glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
727         glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
728         glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
729         EXPECT_GL_NO_ERROR();
730     }
731 }
732 
733 // Test enabling the GL_OES_fbo_render_mipmap extension
TEST_P(WebGLCompatibilityTest,EnableRenderMipmapExtension)734 TEST_P(WebGLCompatibilityTest, EnableRenderMipmapExtension)
735 {
736     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_fbo_render_mipmap"));
737 
738     // This extensions become core in in ES3/WebGL2.
739     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
740 
741     GLTexture texture;
742     glBindTexture(GL_TEXTURE_2D, texture);
743     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
744     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
745 
746     GLFramebuffer fbo;
747     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
748     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
749     EXPECT_GL_NO_ERROR();
750 
751     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
752     EXPECT_GL_ERROR(GL_INVALID_VALUE);
753 
754     if (IsGLExtensionRequestable("GL_OES_fbo_render_mipmap"))
755     {
756         glRequestExtensionANGLE("GL_OES_fbo_render_mipmap");
757         EXPECT_GL_NO_ERROR();
758 
759         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
760         EXPECT_GL_NO_ERROR();
761     }
762 }
763 
764 // Test enabling the GL_EXT_blend_minmax extension
TEST_P(WebGLCompatibilityTest,EnableBlendMinMaxExtension)765 TEST_P(WebGLCompatibilityTest, EnableBlendMinMaxExtension)
766 {
767     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_blend_minmax"));
768 
769     // This extensions become core in in ES3/WebGL2.
770     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
771 
772     glBlendEquation(GL_MIN);
773     EXPECT_GL_ERROR(GL_INVALID_ENUM);
774 
775     glBlendEquation(GL_MAX);
776     EXPECT_GL_ERROR(GL_INVALID_ENUM);
777 
778     if (IsGLExtensionRequestable("GL_EXT_blend_minmax"))
779     {
780         glRequestExtensionANGLE("GL_EXT_blend_minmax");
781         EXPECT_GL_NO_ERROR();
782 
783         glBlendEquation(GL_MIN);
784         glBlendEquation(GL_MAX);
785         EXPECT_GL_NO_ERROR();
786     }
787 }
788 
789 // Test enabling the query extensions
TEST_P(WebGLCompatibilityTest,EnableQueryExtensions)790 TEST_P(WebGLCompatibilityTest, EnableQueryExtensions)
791 {
792     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
793     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
794     EXPECT_FALSE(IsGLExtensionEnabled("GL_CHROMIUM_sync_query"));
795 
796     // This extensions become core in in ES3/WebGL2.
797     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
798 
799     GLQueryEXT badQuery;
800 
801     glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, badQuery);
802     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
803 
804     glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, badQuery);
805     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
806 
807     glBeginQueryEXT(GL_TIME_ELAPSED_EXT, badQuery);
808     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
809 
810     glQueryCounterEXT(GL_TIMESTAMP_EXT, badQuery);
811     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
812 
813     glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, badQuery);
814     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
815 
816     if (IsGLExtensionRequestable("GL_EXT_occlusion_query_boolean"))
817     {
818         glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
819         EXPECT_GL_NO_ERROR();
820 
821         GLQueryEXT query;
822         glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
823         glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
824         EXPECT_GL_NO_ERROR();
825     }
826 
827     if (IsGLExtensionRequestable("GL_EXT_disjoint_timer_query"))
828     {
829         glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
830         EXPECT_GL_NO_ERROR();
831 
832         GLQueryEXT query1;
833         glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query1);
834         glEndQueryEXT(GL_TIME_ELAPSED_EXT);
835         EXPECT_GL_NO_ERROR();
836 
837         GLQueryEXT query2;
838         glQueryCounterEXT(query2, GL_TIMESTAMP_EXT);
839         EXPECT_GL_NO_ERROR();
840     }
841 
842     if (IsGLExtensionRequestable("GL_CHROMIUM_sync_query"))
843     {
844         glRequestExtensionANGLE("GL_CHROMIUM_sync_query");
845         EXPECT_GL_NO_ERROR();
846 
847         GLQueryEXT query;
848         glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query);
849         glEndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
850         EXPECT_GL_NO_ERROR();
851     }
852 }
853 
854 // Test enabling the GL_ANGLE_framebuffer_multisample extension
TEST_P(WebGLCompatibilityTest,EnableFramebufferMultisampleExtension)855 TEST_P(WebGLCompatibilityTest, EnableFramebufferMultisampleExtension)
856 {
857     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_framebuffer_multisample"));
858 
859     // This extensions become core in in ES3/WebGL2.
860     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
861 
862     GLint maxSamples = 0;
863     glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
864     EXPECT_GL_ERROR(GL_INVALID_ENUM);
865 
866     GLRenderbuffer renderbuffer;
867     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
868     glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 1, GL_RGBA4, 1, 1);
869     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
870 
871     if (IsGLExtensionRequestable("GL_ANGLE_framebuffer_multisample"))
872     {
873         glRequestExtensionANGLE("GL_ANGLE_framebuffer_multisample");
874         EXPECT_GL_NO_ERROR();
875 
876         glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
877         EXPECT_GL_NO_ERROR();
878 
879         glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, maxSamples, GL_RGBA4, 1, 1);
880         EXPECT_GL_NO_ERROR();
881     }
882 }
883 
884 // Test enabling the GL_ANGLE_instanced_arrays extension
TEST_P(WebGLCompatibilityTest,EnableInstancedArraysExtensionANGLE)885 TEST_P(WebGLCompatibilityTest, EnableInstancedArraysExtensionANGLE)
886 {
887     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
888 
889     // This extensions become core in in ES3/WebGL2.
890     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
891 
892     GLint divisor = 0;
893     glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
894     EXPECT_GL_ERROR(GL_INVALID_ENUM);
895 
896     glVertexAttribDivisorANGLE(0, 1);
897     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
898 
899     if (IsGLExtensionRequestable("GL_ANGLE_instanced_arrays"))
900     {
901         glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
902         EXPECT_GL_NO_ERROR();
903 
904         glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
905         glVertexAttribDivisorANGLE(0, 1);
906         EXPECT_GL_NO_ERROR();
907     }
908 }
909 
910 // Test enabling the GL_EXT_instanced_arrays extension
TEST_P(WebGLCompatibilityTest,EnableInstancedArraysExtensionEXT)911 TEST_P(WebGLCompatibilityTest, EnableInstancedArraysExtensionEXT)
912 {
913     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_instanced_arrays"));
914 
915     // This extensions become core in in ES3/WebGL2.
916     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
917 
918     GLint divisor = 0;
919     glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
920     EXPECT_GL_ERROR(GL_INVALID_ENUM);
921 
922     glVertexAttribDivisorEXT(0, 1);
923     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
924 
925     if (IsGLExtensionRequestable("GL_EXT_instanced_arrays"))
926     {
927         glRequestExtensionANGLE("GL_EXT_instanced_arrays");
928         EXPECT_GL_NO_ERROR();
929 
930         glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
931         glVertexAttribDivisorEXT(0, 1);
932         EXPECT_GL_NO_ERROR();
933     }
934 }
935 
936 // Test enabling the GL_ANGLE_pack_reverse_row_order extension
TEST_P(WebGLCompatibilityTest,EnablePackReverseRowOrderExtension)937 TEST_P(WebGLCompatibilityTest, EnablePackReverseRowOrderExtension)
938 {
939     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_pack_reverse_row_order"));
940 
941     GLint result = 0;
942     glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
943     EXPECT_GL_ERROR(GL_INVALID_ENUM);
944 
945     glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
946     EXPECT_GL_ERROR(GL_INVALID_ENUM);
947 
948     if (IsGLExtensionRequestable("GL_ANGLE_pack_reverse_row_order"))
949     {
950         glRequestExtensionANGLE("GL_ANGLE_pack_reverse_row_order");
951         EXPECT_GL_NO_ERROR();
952 
953         glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
954         glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
955         EXPECT_GL_NO_ERROR();
956     }
957 }
958 
959 // Test enabling the GL_EXT_unpack_subimage extension
TEST_P(WebGLCompatibilityTest,EnablePackUnpackSubImageExtension)960 TEST_P(WebGLCompatibilityTest, EnablePackUnpackSubImageExtension)
961 {
962     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_unpack_subimage"));
963 
964     // This extensions become core in in ES3/WebGL2.
965     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
966 
967     constexpr GLenum parameters[] = {
968         GL_UNPACK_ROW_LENGTH_EXT,
969         GL_UNPACK_SKIP_ROWS_EXT,
970         GL_UNPACK_SKIP_PIXELS_EXT,
971     };
972 
973     for (GLenum param : parameters)
974     {
975         GLint resultI = 0;
976         glGetIntegerv(param, &resultI);
977         EXPECT_GL_ERROR(GL_INVALID_ENUM);
978 
979         GLfloat resultF = 0.0f;
980         glGetFloatv(param, &resultF);
981         EXPECT_GL_ERROR(GL_INVALID_ENUM);
982 
983         glPixelStorei(param, 0);
984         EXPECT_GL_ERROR(GL_INVALID_ENUM);
985     }
986 
987     if (IsGLExtensionRequestable("GL_EXT_unpack_subimage"))
988     {
989         glRequestExtensionANGLE("GL_EXT_unpack_subimage");
990         EXPECT_GL_NO_ERROR();
991 
992         for (GLenum param : parameters)
993         {
994             GLint resultI = 0;
995             glGetIntegerv(param, &resultI);
996 
997             GLfloat resultF = 0.0f;
998             glGetFloatv(param, &resultF);
999 
1000             glPixelStorei(param, 0);
1001 
1002             EXPECT_GL_NO_ERROR();
1003         }
1004     }
1005 }
1006 
TEST_P(WebGLCompatibilityTest,EnableTextureRectangle)1007 TEST_P(WebGLCompatibilityTest, EnableTextureRectangle)
1008 {
1009     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
1010 
1011     GLTexture texture;
1012     glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
1013     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1014 
1015     GLint minFilter = 0;
1016     glGetTexParameteriv(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, &minFilter);
1017     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1018 
1019     if (IsGLExtensionRequestable("GL_ANGLE_texture_rectangle"))
1020     {
1021         glRequestExtensionANGLE("GL_ANGLE_texture_rectangle");
1022         EXPECT_GL_NO_ERROR();
1023 
1024         EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
1025 
1026         glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
1027         EXPECT_GL_NO_ERROR();
1028 
1029         glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1030                      nullptr);
1031         EXPECT_GL_NO_ERROR();
1032 
1033         glDisableExtensionANGLE("GL_ANGLE_texture_rectangle");
1034         EXPECT_GL_NO_ERROR();
1035 
1036         EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
1037 
1038         glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
1039         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1040     }
1041 }
1042 
1043 // Test enabling the GL_NV_pack_subimage extension
TEST_P(WebGLCompatibilityTest,EnablePackPackSubImageExtension)1044 TEST_P(WebGLCompatibilityTest, EnablePackPackSubImageExtension)
1045 {
1046     EXPECT_FALSE(IsGLExtensionEnabled("GL_NV_pack_subimage"));
1047 
1048     // This extensions become core in in ES3/WebGL2.
1049     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1050 
1051     constexpr GLenum parameters[] = {
1052         GL_PACK_ROW_LENGTH,
1053         GL_PACK_SKIP_ROWS,
1054         GL_PACK_SKIP_PIXELS,
1055     };
1056 
1057     for (GLenum param : parameters)
1058     {
1059         GLint resultI = 0;
1060         glGetIntegerv(param, &resultI);
1061         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1062 
1063         GLfloat resultF = 0.0f;
1064         glGetFloatv(param, &resultF);
1065         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1066 
1067         glPixelStorei(param, 0);
1068         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1069     }
1070 
1071     if (IsGLExtensionRequestable("GL_NV_pack_subimage"))
1072     {
1073         glRequestExtensionANGLE("GL_NV_pack_subimage");
1074         EXPECT_GL_NO_ERROR();
1075 
1076         for (GLenum param : parameters)
1077         {
1078             GLint resultI = 0;
1079             glGetIntegerv(param, &resultI);
1080 
1081             GLfloat resultF = 0.0f;
1082             glGetFloatv(param, &resultF);
1083 
1084             glPixelStorei(param, 0);
1085 
1086             EXPECT_GL_NO_ERROR();
1087         }
1088     }
1089 }
1090 
TEST_P(WebGLCompatibilityTest,EnableRGB8RGBA8Extension)1091 TEST_P(WebGLCompatibilityTest, EnableRGB8RGBA8Extension)
1092 {
1093     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
1094 
1095     // This extensions become core in in ES3/WebGL2.
1096     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1097 
1098     GLRenderbuffer renderbuffer;
1099     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1100     EXPECT_GL_NO_ERROR();
1101 
1102     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 1, 1);
1103     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1104 
1105     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
1106     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1107 
1108     if (IsGLExtensionRequestable("GL_OES_rgb8_rgba8"))
1109     {
1110         glRequestExtensionANGLE("GL_OES_rgb8_rgba8");
1111         EXPECT_GL_NO_ERROR();
1112 
1113         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
1114 
1115         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 1, 1);
1116         EXPECT_GL_NO_ERROR();
1117 
1118         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
1119         EXPECT_GL_NO_ERROR();
1120     }
1121 }
1122 
1123 // Test enabling the GL_ANGLE_framebuffer_blit extension
TEST_P(WebGLCompatibilityTest,EnableFramebufferBlitExtension)1124 TEST_P(WebGLCompatibilityTest, EnableFramebufferBlitExtension)
1125 {
1126     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit"));
1127 
1128     // This extensions become core in in ES3/WebGL2.
1129     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1130 
1131     GLFramebuffer fbo;
1132 
1133     glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
1134     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1135 
1136     GLint result;
1137     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_ANGLE, &result);
1138     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1139 
1140     glBlitFramebufferANGLE(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1141     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1142 
1143     if (IsGLExtensionRequestable("GL_ANGLE_framebuffer_blit"))
1144     {
1145         glRequestExtensionANGLE("GL_ANGLE_framebuffer_blit");
1146         EXPECT_GL_NO_ERROR();
1147 
1148         glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
1149         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_ANGLE, &result);
1150         EXPECT_GL_NO_ERROR();
1151     }
1152 }
1153 
1154 // Test enabling the GL_OES_get_program_binary extension
TEST_P(WebGLCompatibilityTest,EnableProgramBinaryExtension)1155 TEST_P(WebGLCompatibilityTest, EnableProgramBinaryExtension)
1156 {
1157     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_get_program_binary"));
1158 
1159     // This extensions become core in in ES3/WebGL2.
1160     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1161 
1162     GLint result           = 0;
1163     GLint numBinaryFormats = 0;
1164     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinaryFormats);
1165     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1166 
1167     glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &result);
1168     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1169 
1170     constexpr char kVS[] =
1171         R"(void main()
1172 {
1173     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
1174 })";
1175     constexpr char kFS[] =
1176         R"(precision highp float;
1177 void main()
1178 {
1179     gl_FragColor = vec4(1.0);
1180 })";
1181     ANGLE_GL_PROGRAM(program, kVS, kFS);
1182 
1183     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &result);
1184     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1185 
1186     uint8_t tempArray[512];
1187     GLenum tempFormat  = 0;
1188     GLsizei tempLength = 0;
1189     glGetProgramBinaryOES(program, static_cast<GLsizei>(ArraySize(tempArray)), &tempLength,
1190                           &tempFormat, tempArray);
1191     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1192 
1193     if (IsGLExtensionRequestable("GL_OES_get_program_binary"))
1194     {
1195         glRequestExtensionANGLE("GL_OES_get_program_binary");
1196         EXPECT_GL_NO_ERROR();
1197 
1198         glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinaryFormats);
1199         // No use to test further if no binary formats are supported
1200         ANGLE_SKIP_TEST_IF(numBinaryFormats < 1);
1201 
1202         glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &result);
1203         EXPECT_GL_NO_ERROR();
1204 
1205         GLint binaryLength = 0;
1206         glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
1207         EXPECT_GL_NO_ERROR();
1208 
1209         GLenum binaryFormat;
1210         GLsizei writeLength = 0;
1211         std::vector<uint8_t> binary(binaryLength);
1212         glGetProgramBinaryOES(program, binaryLength, &writeLength, &binaryFormat, binary.data());
1213         EXPECT_GL_NO_ERROR();
1214 
1215         glProgramBinaryOES(program, binaryFormat, binary.data(), binaryLength);
1216         EXPECT_GL_NO_ERROR();
1217     }
1218 }
1219 
1220 // Test enabling the GL_OES_vertex_array_object extension
TEST_P(WebGLCompatibilityTest,EnableVertexArrayExtension)1221 TEST_P(WebGLCompatibilityTest, EnableVertexArrayExtension)
1222 {
1223     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_vertex_array_object"));
1224 
1225     // This extensions become core in in ES3/WebGL2.
1226     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1227 
1228     GLint result = 0;
1229     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &result);
1230     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1231 
1232     // Expect that GL_OES_vertex_array_object is always available.  It is implemented in the GL
1233     // frontend.
1234     EXPECT_TRUE(IsGLExtensionRequestable("GL_OES_vertex_array_object"));
1235 
1236     glRequestExtensionANGLE("GL_OES_vertex_array_object");
1237     EXPECT_GL_NO_ERROR();
1238 
1239     EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_vertex_array_object"));
1240 
1241     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &result);
1242     EXPECT_GL_NO_ERROR();
1243 
1244     GLuint vao = 0;
1245     glGenVertexArraysOES(0, &vao);
1246     EXPECT_GL_NO_ERROR();
1247 
1248     glBindVertexArrayOES(vao);
1249     EXPECT_GL_NO_ERROR();
1250 
1251     glDeleteVertexArraysOES(1, &vao);
1252     EXPECT_GL_NO_ERROR();
1253 }
1254 
1255 // Verify that the context generates the correct error when the framebuffer attachments are
1256 // different sizes
TEST_P(WebGLCompatibilityTest,FramebufferAttachmentSizeMismatch)1257 TEST_P(WebGLCompatibilityTest, FramebufferAttachmentSizeMismatch)
1258 {
1259     GLFramebuffer fbo;
1260     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1261 
1262     GLTexture textures[2];
1263     glBindTexture(GL_TEXTURE_2D, textures[0]);
1264     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1265     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
1266 
1267     ASSERT_GL_NO_ERROR();
1268     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1269 
1270     GLRenderbuffer renderbuffer;
1271     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1272     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 3, 3);
1273     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
1274 
1275     ASSERT_GL_NO_ERROR();
1276     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1277                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
1278 
1279     if (IsGLExtensionRequestable("GL_EXT_draw_buffers"))
1280     {
1281         glRequestExtensionANGLE("GL_EXT_draw_buffers");
1282         EXPECT_GL_NO_ERROR();
1283         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_draw_buffers"));
1284 
1285         glBindTexture(GL_TEXTURE_2D, textures[1]);
1286         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1287         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
1288         ASSERT_GL_NO_ERROR();
1289 
1290         ASSERT_GL_NO_ERROR();
1291         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1292                          glCheckFramebufferStatus(GL_FRAMEBUFFER));
1293 
1294         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
1295 
1296         ASSERT_GL_NO_ERROR();
1297         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1298 
1299         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1300 
1301         ASSERT_GL_NO_ERROR();
1302         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1303                          glCheckFramebufferStatus(GL_FRAMEBUFFER));
1304     }
1305 }
1306 
1307 // Test that client-side array buffers are forbidden in WebGL mode
TEST_P(WebGLCompatibilityTest,ForbidsClientSideArrayBuffer)1308 TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
1309 {
1310     constexpr char kVS[] =
1311         R"(attribute vec3 a_pos;
1312 void main()
1313 {
1314     gl_Position = vec4(a_pos, 1.0);
1315 })";
1316 
1317     constexpr char kFS[] =
1318         R"(precision highp float;
1319 void main()
1320 {
1321     gl_FragColor = vec4(1.0);
1322 })";
1323 
1324     ANGLE_GL_PROGRAM(program, kVS, kFS);
1325 
1326     GLint posLocation = glGetAttribLocation(program, "a_pos");
1327     ASSERT_NE(-1, posLocation);
1328     glUseProgram(program);
1329 
1330     const auto &vertices = GetQuadVertices();
1331     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
1332     glEnableVertexAttribArray(posLocation);
1333 
1334     ASSERT_GL_NO_ERROR();
1335     glDrawArrays(GL_TRIANGLES, 0, 6);
1336     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1337 }
1338 
1339 // Test that client-side element array buffers are forbidden in WebGL mode
TEST_P(WebGLCompatibilityTest,ForbidsClientSideElementBuffer)1340 TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
1341 {
1342     constexpr char kVS[] =
1343         R"(attribute vec3 a_pos;
1344 void main()
1345 {
1346     gl_Position = vec4(a_pos, 1.0);
1347 })";
1348 
1349     constexpr char kFS[] =
1350         R"(precision highp float;
1351 void main()
1352 {
1353     gl_FragColor = vec4(1.0);
1354 })";
1355 
1356     ANGLE_GL_PROGRAM(program, kVS, kFS);
1357 
1358     GLint posLocation = glGetAttribLocation(program, "a_pos");
1359     ASSERT_NE(-1, posLocation);
1360     glUseProgram(program);
1361 
1362     const auto &vertices = GetQuadVertices();
1363 
1364     GLBuffer vertexBuffer;
1365     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1366     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1367                  GL_STATIC_DRAW);
1368 
1369     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1370     glEnableVertexAttribArray(posLocation);
1371 
1372     ASSERT_GL_NO_ERROR();
1373 
1374     // Use the pointer with value of 1 for indices instead of an actual pointer because WebGL also
1375     // enforces that the top bit of indices must be 0 (i.e. offset >= 0) and would generate
1376     // GL_INVALID_VALUE in that case. Using a null pointer gets caught by another check.
1377     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(intptr_t(1)));
1378     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1379 }
1380 
1381 // Test that client-side array buffers are forbidden even if the program doesn't use the attribute
TEST_P(WebGLCompatibilityTest,ForbidsClientSideArrayBufferEvenNotUsedOnes)1382 TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBufferEvenNotUsedOnes)
1383 {
1384     constexpr char kVS[] =
1385         R"(void main()
1386 {
1387     gl_Position = vec4(1.0);
1388 })";
1389 
1390     constexpr char kFS[] =
1391         R"(precision highp float;
1392 void main()
1393 {
1394     gl_FragColor = vec4(1.0);
1395 })";
1396 
1397     ANGLE_GL_PROGRAM(program, kVS, kFS);
1398 
1399     glUseProgram(program);
1400 
1401     const auto &vertices = GetQuadVertices();
1402     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
1403     glEnableVertexAttribArray(0);
1404 
1405     ASSERT_GL_NO_ERROR();
1406     glDrawArrays(GL_TRIANGLES, 0, 6);
1407     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1408 }
1409 
1410 // Test that passing a null pixel data pointer to TexSubImage calls generates an INVALID_VALUE error
TEST_P(WebGLCompatibilityTest,NullPixelDataForSubImage)1411 TEST_P(WebGLCompatibilityTest, NullPixelDataForSubImage)
1412 {
1413     // glTexSubImage2D
1414     {
1415         GLTexture texture;
1416         glBindTexture(GL_TEXTURE_2D, texture);
1417 
1418         // TexImage with null data - OK
1419         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1420         EXPECT_GL_NO_ERROR();
1421 
1422         // TexSubImage with zero size and null data - OK
1423         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1424         EXPECT_GL_NO_ERROR();
1425 
1426         // TexSubImage with non-zero size and null data - Invalid value
1427         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1428         EXPECT_GL_ERROR(GL_INVALID_VALUE);
1429     }
1430 
1431     // glTexSubImage3D
1432     if (getClientMajorVersion() >= 3)
1433     {
1434         GLTexture texture;
1435         glBindTexture(GL_TEXTURE_3D, texture);
1436 
1437         // TexImage with null data - OK
1438         glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1439         EXPECT_GL_NO_ERROR();
1440 
1441         // TexSubImage with zero size and null data - OK
1442         glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1443         EXPECT_GL_NO_ERROR();
1444 
1445         // TexSubImage with non-zero size and null data - Invalid value
1446         glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1447         EXPECT_GL_ERROR(GL_INVALID_VALUE);
1448     }
1449 }
1450 
1451 // Tests the WebGL requirement of having the same stencil mask, writemask and ref for front and back
1452 // (when stencil testing is enabled)
TestDifferentStencilMaskAndRef(GLenum errIfMismatch)1453 void WebGLCompatibilityTest::TestDifferentStencilMaskAndRef(GLenum errIfMismatch)
1454 {
1455     // Run the test in an FBO to make sure we have some stencil bits.
1456     GLRenderbuffer renderbuffer;
1457     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1458     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
1459 
1460     GLFramebuffer framebuffer;
1461     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1462     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1463                               renderbuffer);
1464 
1465     ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
1466                      "void main() { gl_FragColor = vec4(0, 1, 0, 1); }");
1467     glUseProgram(program);
1468     ASSERT_GL_NO_ERROR();
1469 
1470     // Having ref and mask the same for front and back is valid.
1471     glStencilMask(255);
1472     glStencilFunc(GL_ALWAYS, 0, 255);
1473     glDrawArrays(GL_TRIANGLES, 0, 6);
1474     ASSERT_GL_NO_ERROR();
1475 
1476     // Having a different front - back write mask generates an error.
1477     glStencilMaskSeparate(GL_FRONT, 1);
1478     glDrawArrays(GL_TRIANGLES, 0, 6);
1479     EXPECT_GL_ERROR(errIfMismatch);
1480 
1481     // Setting both write masks separately to the same value is valid.
1482     glStencilMaskSeparate(GL_BACK, 1);
1483     glDrawArrays(GL_TRIANGLES, 0, 6);
1484     ASSERT_GL_NO_ERROR();
1485 
1486     // Having a different stencil front - back mask generates an error
1487     glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
1488     glDrawArrays(GL_TRIANGLES, 0, 6);
1489     EXPECT_GL_ERROR(errIfMismatch);
1490 
1491     // Setting both masks separately to the same value is valid.
1492     glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
1493     glDrawArrays(GL_TRIANGLES, 0, 6);
1494     ASSERT_GL_NO_ERROR();
1495 
1496     // Having a different stencil front - back reference generates an error
1497     glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
1498     glDrawArrays(GL_TRIANGLES, 0, 6);
1499     EXPECT_GL_ERROR(errIfMismatch);
1500 
1501     // Setting both references separately to the same value is valid.
1502     glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
1503     glDrawArrays(GL_TRIANGLES, 0, 6);
1504     ASSERT_GL_NO_ERROR();
1505 
1506     // Using different stencil funcs, everything being equal is valid.
1507     glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
1508     glDrawArrays(GL_TRIANGLES, 0, 6);
1509     ASSERT_GL_NO_ERROR();
1510 }
1511 
TEST_P(WebGLCompatibilityTest,StencilTestEnabledDisallowsDifferentStencilMaskAndRef)1512 TEST_P(WebGLCompatibilityTest, StencilTestEnabledDisallowsDifferentStencilMaskAndRef)
1513 {
1514     glEnable(GL_STENCIL_TEST);
1515     TestDifferentStencilMaskAndRef(GL_INVALID_OPERATION);
1516 }
1517 
TEST_P(WebGLCompatibilityTest,StencilTestDisabledAllowsDifferentStencilMaskAndRef)1518 TEST_P(WebGLCompatibilityTest, StencilTestDisabledAllowsDifferentStencilMaskAndRef)
1519 {
1520     glDisable(GL_STENCIL_TEST);
1521     TestDifferentStencilMaskAndRef(GL_NO_ERROR);
1522 }
1523 
1524 // Test that GL_FIXED is forbidden
TEST_P(WebGLCompatibilityTest,ForbidsGLFixed)1525 TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
1526 {
1527     GLBuffer buffer;
1528     glBindBuffer(GL_ARRAY_BUFFER, buffer);
1529     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1530 
1531     glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1532     ASSERT_GL_NO_ERROR();
1533 
1534     glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
1535     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1536 }
1537 
1538 // Test the WebGL limit of 255 for the attribute stride
TEST_P(WebGLCompatibilityTest,MaxStride)1539 TEST_P(WebGLCompatibilityTest, MaxStride)
1540 {
1541     GLBuffer buffer;
1542     glBindBuffer(GL_ARRAY_BUFFER, buffer);
1543     glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
1544 
1545     glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
1546     ASSERT_GL_NO_ERROR();
1547 
1548     glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
1549     EXPECT_GL_ERROR(GL_INVALID_VALUE);
1550 }
1551 
1552 // Test the checks for OOB reads in the vertex buffers, non-instanced version
TEST_P(WebGLCompatibilityTest,DrawArraysBufferOutOfBoundsNonInstanced)1553 TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
1554 {
1555     constexpr char kVS[] =
1556         R"(attribute float a_pos;
1557 void main()
1558 {
1559     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1560 })";
1561 
1562     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1563     GLint posLocation = glGetAttribLocation(program, "a_pos");
1564     ASSERT_NE(-1, posLocation);
1565     glUseProgram(program);
1566 
1567     GLBuffer buffer;
1568     glBindBuffer(GL_ARRAY_BUFFER, buffer);
1569     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1570 
1571     glEnableVertexAttribArray(posLocation);
1572 
1573     // Test touching the last element is valid.
1574     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1575                           reinterpret_cast<const void *>(12));
1576     glDrawArrays(GL_POINTS, 0, 4);
1577     ASSERT_GL_NO_ERROR();
1578 
1579     // Test touching the last element + 1 is invalid.
1580     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1581                           reinterpret_cast<const void *>(13));
1582     glDrawArrays(GL_POINTS, 0, 4);
1583     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1584 
1585     // Test touching the last element is valid, using a stride.
1586     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2,
1587                           reinterpret_cast<const void *>(9));
1588     glDrawArrays(GL_POINTS, 0, 4);
1589     ASSERT_GL_NO_ERROR();
1590 
1591     // Test touching the last element + 1 is invalid, using a stride.
1592     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2,
1593                           reinterpret_cast<const void *>(10));
1594     glDrawArrays(GL_POINTS, 0, 4);
1595     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1596 
1597     // Test any offset is valid if no vertices are drawn.
1598     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1599                           reinterpret_cast<const void *>(32));
1600     glDrawArrays(GL_POINTS, 0, 0);
1601     ASSERT_GL_NO_ERROR();
1602 
1603     // Test a case of overflow that could give a max vertex that's negative
1604     constexpr GLint kIntMax = std::numeric_limits<GLint>::max();
1605     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1606     glDrawArrays(GL_POINTS, kIntMax, kIntMax);
1607     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1608 }
1609 
1610 // Test that index values outside of the 32-bit integer range do not read out of bounds
TEST_P(WebGLCompatibilityTest,LargeIndexRange)1611 TEST_P(WebGLCompatibilityTest, LargeIndexRange)
1612 {
1613     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_element_index_uint"));
1614 
1615     constexpr char kVS[] =
1616         R"(attribute vec4 a_Position;
1617 void main()
1618 {
1619     gl_Position = a_Position;
1620 })";
1621 
1622     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1623     glUseProgram(program);
1624 
1625     glEnableVertexAttribArray(glGetAttribLocation(program, "a_Position"));
1626 
1627     constexpr float kVertexData[] = {
1628         1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1629     };
1630 
1631     GLBuffer vertexBuffer;
1632     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1633     glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STREAM_DRAW);
1634 
1635     constexpr GLuint kMaxIntAsGLuint = static_cast<GLuint>(std::numeric_limits<GLint>::max());
1636     constexpr GLuint kIndexData[]    = {
1637         kMaxIntAsGLuint,
1638         kMaxIntAsGLuint + 1,
1639         kMaxIntAsGLuint + 2,
1640         kMaxIntAsGLuint + 3,
1641     };
1642 
1643     GLBuffer indexBuffer;
1644     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBuffer);
1645     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexData), kIndexData, GL_DYNAMIC_DRAW);
1646 
1647     EXPECT_GL_NO_ERROR();
1648 
1649     // First index is representable as 32-bit int but second is not
1650     glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, 0);
1651     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1652 
1653     // Neither index is representable as 32-bit int
1654     glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, reinterpret_cast<void *>(sizeof(GLuint) * 2));
1655     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1656 }
1657 
1658 // Test for drawing with a null index buffer
TEST_P(WebGLCompatibilityTest,NullIndexBuffer)1659 TEST_P(WebGLCompatibilityTest, NullIndexBuffer)
1660 {
1661     constexpr char kVS[] =
1662         R"(attribute float a_pos;
1663 void main()
1664 {
1665     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1666 })";
1667 
1668     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1669     glUseProgram(program);
1670 
1671     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1672     glEnableVertexAttribArray(0);
1673 
1674     glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_BYTE, 0);
1675     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1676 }
1677 
1678 // Test the checks for OOB reads in the vertex buffers, instanced version
TEST_P(WebGL2CompatibilityTest,DrawArraysBufferOutOfBoundsInstanced)1679 TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
1680 {
1681     constexpr char kVS[] =
1682         R"(attribute float a_pos;
1683 attribute float a_w;
1684 void main()
1685 {
1686     gl_Position = vec4(a_pos, a_pos, a_pos, a_w);
1687 })";
1688 
1689     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1690     GLint posLocation = glGetAttribLocation(program, "a_pos");
1691     GLint wLocation   = glGetAttribLocation(program, "a_w");
1692     ASSERT_NE(-1, posLocation);
1693     ASSERT_NE(-1, wLocation);
1694     glUseProgram(program);
1695 
1696     GLBuffer buffer;
1697     glBindBuffer(GL_ARRAY_BUFFER, buffer);
1698     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1699 
1700     glEnableVertexAttribArray(posLocation);
1701     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1702     glVertexAttribDivisor(posLocation, 0);
1703 
1704     glEnableVertexAttribArray(wLocation);
1705     glVertexAttribDivisor(wLocation, 1);
1706 
1707     // Test touching the last element is valid.
1708     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1709                           reinterpret_cast<const void *>(12));
1710     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1711     ASSERT_GL_NO_ERROR();
1712 
1713     // Test touching the last element + 1 is invalid.
1714     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1715                           reinterpret_cast<const void *>(13));
1716     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1717     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1718 
1719     // Test touching the last element is valid, using a stride.
1720     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2,
1721                           reinterpret_cast<const void *>(9));
1722     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1723     ASSERT_GL_NO_ERROR();
1724 
1725     // Test touching the last element + 1 is invalid, using a stride.
1726     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2,
1727                           reinterpret_cast<const void *>(10));
1728     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1729     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1730 
1731     // Test any offset is valid if no vertices are drawn.
1732     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1733                           reinterpret_cast<const void *>(32));
1734     glDrawArraysInstanced(GL_POINTS, 0, 0, 1);
1735     ASSERT_GL_NO_ERROR();
1736 
1737     // Test any offset is valid if no primitives are drawn.
1738     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1739                           reinterpret_cast<const void *>(32));
1740     glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
1741     ASSERT_GL_NO_ERROR();
1742 }
1743 
1744 // Test the checks for OOB reads in the vertex buffers, ANGLE_instanced_arrays version
TEST_P(WebGLCompatibilityTest,DrawArraysBufferOutOfBoundsInstancedANGLE)1745 TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsInstancedANGLE)
1746 {
1747     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_ANGLE_instanced_arrays"));
1748     glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
1749     EXPECT_GL_NO_ERROR();
1750 
1751     constexpr char kVS[] =
1752         R"(attribute float a_pos;
1753 attribute float a_w;
1754 void main()
1755 {
1756     gl_Position = vec4(a_pos, a_pos, a_pos, a_w);
1757 })";
1758 
1759     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1760     GLint posLocation = glGetAttribLocation(program, "a_pos");
1761     GLint wLocation   = glGetAttribLocation(program, "a_w");
1762     ASSERT_NE(-1, posLocation);
1763     ASSERT_NE(-1, wLocation);
1764     glUseProgram(program);
1765 
1766     GLBuffer buffer;
1767     glBindBuffer(GL_ARRAY_BUFFER, buffer);
1768     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1769 
1770     glEnableVertexAttribArray(posLocation);
1771     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1772     glVertexAttribDivisorANGLE(posLocation, 0);
1773 
1774     glEnableVertexAttribArray(wLocation);
1775     glVertexAttribDivisorANGLE(wLocation, 1);
1776 
1777     // Test touching the last element is valid.
1778     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1779                           reinterpret_cast<const void *>(12));
1780     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1781     ASSERT_GL_NO_ERROR() << "touching the last element.";
1782 
1783     // Test touching the last element + 1 is invalid.
1784     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1785                           reinterpret_cast<const void *>(13));
1786     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1787     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "touching the last element + 1.";
1788 
1789     // Test touching the last element is valid, using a stride.
1790     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2,
1791                           reinterpret_cast<const void *>(9));
1792     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1793     ASSERT_GL_NO_ERROR() << "touching the last element using a stride.";
1794 
1795     // Test touching the last element + 1 is invalid, using a stride.
1796     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2,
1797                           reinterpret_cast<const void *>(10));
1798     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1799     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "touching the last element + 1 using a stride.";
1800 
1801     // Test any offset is valid if no vertices are drawn.
1802     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1803                           reinterpret_cast<const void *>(32));
1804     glDrawArraysInstancedANGLE(GL_POINTS, 0, 0, 1);
1805     ASSERT_GL_NO_ERROR() << "any offset with no vertices.";
1806 
1807     // Test any offset is valid if no primitives are drawn.
1808     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0,
1809                           reinterpret_cast<const void *>(32));
1810     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 0);
1811     ASSERT_GL_NO_ERROR() << "any offset with primitives.";
1812 }
1813 
1814 // Test the checks for OOB reads in the index buffer
TEST_P(WebGLCompatibilityTest,DrawElementsBufferOutOfBoundsInIndexBuffer)1815 TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
1816 {
1817     constexpr char kVS[] =
1818         R"(attribute float a_pos;
1819 void main()
1820 {
1821     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1822 })";
1823 
1824     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1825     GLint posLocation = glGetAttribLocation(program, "a_pos");
1826     ASSERT_NE(-1, posLocation);
1827     glUseProgram(program);
1828 
1829     GLBuffer vertexBuffer;
1830     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1831     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1832 
1833     glEnableVertexAttribArray(posLocation);
1834     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1835 
1836     const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
1837 
1838     GLBuffer indexBuffer;
1839     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
1840     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
1841     ASSERT_GL_NO_ERROR();
1842 
1843     // Test touching the last index is valid
1844     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(4));
1845     ASSERT_GL_NO_ERROR();
1846 
1847     // Test touching the last + 1 element is invalid
1848     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(5));
1849     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1850 
1851     // Test any offset if valid if count is zero
1852     glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(42));
1853     ASSERT_GL_NO_ERROR();
1854 
1855     // Test touching the first index is valid
1856     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(4));
1857     ASSERT_GL_NO_ERROR();
1858 
1859     // Test touching the first - 1 index is invalid
1860     // The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
1861     // the historic behavior of WebGL implementations
1862     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE,
1863                    reinterpret_cast<const void *>(static_cast<ptrdiff_t>(0) - 1));
1864     EXPECT_GL_ERROR(GL_INVALID_VALUE);
1865 }
1866 
1867 // Test the checks for OOB in vertex buffers caused by indices, non-instanced version
TEST_P(WebGLCompatibilityTest,DrawElementsBufferOutOfBoundsInVertexBuffer)1868 TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInVertexBuffer)
1869 {
1870     constexpr char kVS[] =
1871         R"(attribute float a_pos;
1872 void main()
1873 {
1874     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1875 })";
1876 
1877     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1878     GLint posLocation = glGetAttribLocation(program, "a_pos");
1879     ASSERT_NE(-1, posLocation);
1880     glUseProgram(program);
1881 
1882     GLBuffer vertexBuffer;
1883     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1884     glBufferData(GL_ARRAY_BUFFER, 8, nullptr, GL_STATIC_DRAW);
1885 
1886     glEnableVertexAttribArray(posLocation);
1887     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1888 
1889     const uint8_t testIndices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 255};
1890 
1891     GLBuffer indexBuffer;
1892     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
1893     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(testIndices), testIndices, GL_STATIC_DRAW);
1894     ASSERT_GL_NO_ERROR();
1895 
1896     // Test touching the end of the vertex buffer is valid
1897     glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(7));
1898     ASSERT_GL_NO_ERROR();
1899 
1900     // Test touching just after the end of the vertex buffer is invalid
1901     glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(8));
1902     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1903 
1904     // Test touching the whole vertex buffer is valid
1905     glDrawElements(GL_POINTS, 8, GL_UNSIGNED_BYTE, nullptr);
1906     ASSERT_GL_NO_ERROR();
1907 
1908     // Test an index that would be negative
1909     glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(9));
1910     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1911 }
1912 
1913 // Test depth range with 'near' more or less than 'far.'
TEST_P(WebGLCompatibilityTest,DepthRange)1914 TEST_P(WebGLCompatibilityTest, DepthRange)
1915 {
1916     glDepthRangef(0, 1);
1917     ASSERT_GL_NO_ERROR();
1918 
1919     glDepthRangef(.5, .5);
1920     ASSERT_GL_NO_ERROR();
1921 
1922     glDepthRangef(1, 0);
1923     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1924 }
1925 
1926 // Test all blend function combinations.
1927 // In WebGL it is invalid to combine constant color with constant alpha.
TEST_P(WebGLCompatibilityTest,BlendWithConstantColor)1928 TEST_P(WebGLCompatibilityTest, BlendWithConstantColor)
1929 {
1930     constexpr GLenum srcFunc[] = {
1931         GL_ZERO,
1932         GL_ONE,
1933         GL_SRC_COLOR,
1934         GL_ONE_MINUS_SRC_COLOR,
1935         GL_DST_COLOR,
1936         GL_ONE_MINUS_DST_COLOR,
1937         GL_SRC_ALPHA,
1938         GL_ONE_MINUS_SRC_ALPHA,
1939         GL_DST_ALPHA,
1940         GL_ONE_MINUS_DST_ALPHA,
1941         GL_CONSTANT_COLOR,
1942         GL_ONE_MINUS_CONSTANT_COLOR,
1943         GL_CONSTANT_ALPHA,
1944         GL_ONE_MINUS_CONSTANT_ALPHA,
1945         GL_SRC_ALPHA_SATURATE,
1946     };
1947 
1948     constexpr GLenum dstFunc[] = {
1949         GL_ZERO,           GL_ONE,
1950         GL_SRC_COLOR,      GL_ONE_MINUS_SRC_COLOR,
1951         GL_DST_COLOR,      GL_ONE_MINUS_DST_COLOR,
1952         GL_SRC_ALPHA,      GL_ONE_MINUS_SRC_ALPHA,
1953         GL_DST_ALPHA,      GL_ONE_MINUS_DST_ALPHA,
1954         GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
1955         GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA,
1956     };
1957 
1958     for (GLenum src : srcFunc)
1959     {
1960         for (GLenum dst : dstFunc)
1961         {
1962             glBlendFunc(src, dst);
1963             CheckBlendFunctions(src, dst);
1964             glBlendFuncSeparate(src, dst, GL_ONE, GL_ONE);
1965             CheckBlendFunctions(src, dst);
1966         }
1967     }
1968 
1969     // Ensure the same semantics for indexed blendFunc
1970     if (IsGLExtensionRequestable("GL_OES_draw_buffers_indexed"))
1971     {
1972         glRequestExtensionANGLE("GL_OES_draw_buffers_indexed");
1973         EXPECT_GL_NO_ERROR();
1974         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
1975 
1976         for (GLenum src : srcFunc)
1977         {
1978             for (GLenum dst : dstFunc)
1979             {
1980                 glBlendFunciOES(0, src, dst);
1981                 CheckBlendFunctions(src, dst);
1982                 glBlendFuncSeparateiOES(0, src, dst, GL_ONE, GL_ONE);
1983                 CheckBlendFunctions(src, dst);
1984             }
1985         }
1986     }
1987 }
1988 
1989 // Test draw state validation and invalidation wrt indexed blendFunc.
TEST_P(WebGLCompatibilityTest,IndexedBlendWithConstantColorInvalidation)1990 TEST_P(WebGLCompatibilityTest, IndexedBlendWithConstantColorInvalidation)
1991 {
1992     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
1993     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_OES_draw_buffers_indexed"));
1994 
1995     glRequestExtensionANGLE("GL_OES_draw_buffers_indexed");
1996     EXPECT_GL_NO_ERROR();
1997     EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
1998 
1999     constexpr char kVS[] =
2000         R"(#version 300 es
2001 void main()
2002 {
2003     gl_PointSize = 1.0;
2004     gl_Position = vec4(0, 0, 0, 1);
2005 })";
2006 
2007     constexpr char kFS[] =
2008         R"(#version 300 es
2009 precision lowp float;
2010 layout(location = 0) out vec4 o_color0;
2011 layout(location = 1) out vec4 o_color1;
2012 void main()
2013 {
2014     o_color0 = vec4(1, 0, 0, 1);
2015     o_color1 = vec4(0, 1, 0, 1);
2016 })";
2017 
2018     ANGLE_GL_PROGRAM(program, kVS, kFS);
2019     glUseProgram(program);
2020 
2021     glDisable(GL_BLEND);
2022     glEnableiOES(GL_BLEND, 0);
2023     glEnableiOES(GL_BLEND, 1);
2024 
2025     GLTexture texture1;
2026     glBindTexture(GL_TEXTURE_2D, texture1);
2027     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2028     EXPECT_GL_NO_ERROR();
2029 
2030     GLTexture texture2;
2031     glBindTexture(GL_TEXTURE_2D, texture2);
2032     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2033     EXPECT_GL_NO_ERROR();
2034 
2035     GLFramebuffer fbo;
2036     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2037     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
2038     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
2039     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2040 
2041     GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
2042     glDrawBuffers(2, drawbuffers);
2043 
2044     glDrawArrays(GL_POINTS, 0, 1);
2045     EXPECT_GL_NO_ERROR();
2046 
2047     // Force-invalidate draw call
2048     glBlendFuncSeparateiOES(0, GL_CONSTANT_COLOR, GL_CONSTANT_COLOR, GL_CONSTANT_ALPHA,
2049                             GL_CONSTANT_ALPHA);
2050     EXPECT_GL_NO_ERROR();
2051 
2052     glBlendFuncSeparateiOES(1, GL_CONSTANT_ALPHA, GL_CONSTANT_ALPHA, GL_CONSTANT_COLOR,
2053                             GL_CONSTANT_COLOR);
2054     EXPECT_GL_NO_ERROR();
2055 
2056     glDrawArrays(GL_POINTS, 0, 1);
2057     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2058 }
2059 
2060 // Test getIndexedParameter wrt GL_OES_draw_buffers_indexed.
TEST_P(WebGLCompatibilityTest,DrawBuffersIndexedGetIndexedParameter)2061 TEST_P(WebGLCompatibilityTest, DrawBuffersIndexedGetIndexedParameter)
2062 {
2063     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
2064     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_OES_draw_buffers_indexed"));
2065 
2066     GLint value;
2067     GLint data[4];
2068 
2069     glGetIntegeri_v(GL_BLEND_EQUATION_RGB, 0, &value);
2070     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2071     glGetIntegeri_v(GL_BLEND_EQUATION_ALPHA, 0, &value);
2072     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2073     glGetIntegeri_v(GL_BLEND_SRC_RGB, 0, &value);
2074     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2075     glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 0, &value);
2076     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2077     glGetIntegeri_v(GL_BLEND_DST_RGB, 0, &value);
2078     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2079     glGetIntegeri_v(GL_BLEND_DST_ALPHA, 0, &value);
2080     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2081     glGetIntegeri_v(GL_COLOR_WRITEMASK, 0, data);
2082     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2083 
2084     glRequestExtensionANGLE("GL_OES_draw_buffers_indexed");
2085     EXPECT_GL_NO_ERROR();
2086     EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
2087 
2088     glDisable(GL_BLEND);
2089     glEnableiOES(GL_BLEND, 0);
2090     glBlendEquationSeparateiOES(0, GL_FUNC_ADD, GL_FUNC_SUBTRACT);
2091     glBlendFuncSeparateiOES(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ZERO);
2092     glColorMaskiOES(0, true, false, true, false);
2093     EXPECT_GL_NO_ERROR();
2094 
2095     EXPECT_EQ(true, glIsEnablediOES(GL_BLEND, 0));
2096     EXPECT_GL_NO_ERROR();
2097     glGetIntegeri_v(GL_BLEND_EQUATION_RGB, 0, &value);
2098     EXPECT_GL_NO_ERROR();
2099     EXPECT_EQ(GL_FUNC_ADD, value);
2100     glGetIntegeri_v(GL_BLEND_EQUATION_ALPHA, 0, &value);
2101     EXPECT_GL_NO_ERROR();
2102     EXPECT_EQ(GL_FUNC_SUBTRACT, value);
2103     glGetIntegeri_v(GL_BLEND_SRC_RGB, 0, &value);
2104     EXPECT_GL_NO_ERROR();
2105     EXPECT_EQ(GL_SRC_ALPHA, value);
2106     glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 0, &value);
2107     EXPECT_GL_NO_ERROR();
2108     EXPECT_EQ(GL_ZERO, value);
2109     glGetIntegeri_v(GL_BLEND_DST_RGB, 0, &value);
2110     EXPECT_GL_NO_ERROR();
2111     EXPECT_EQ(GL_ONE_MINUS_SRC_ALPHA, value);
2112     glGetIntegeri_v(GL_BLEND_DST_ALPHA, 0, &value);
2113     EXPECT_GL_NO_ERROR();
2114     EXPECT_EQ(GL_ZERO, value);
2115     glGetIntegeri_v(GL_COLOR_WRITEMASK, 0, data);
2116     EXPECT_GL_NO_ERROR();
2117     EXPECT_EQ(true, data[0]);
2118     EXPECT_EQ(false, data[1]);
2119     EXPECT_EQ(true, data[2]);
2120     EXPECT_EQ(false, data[3]);
2121 }
2122 
2123 // Test that binding/querying uniforms and attributes with invalid names generates errors
TEST_P(WebGLCompatibilityTest,InvalidAttributeAndUniformNames)2124 TEST_P(WebGLCompatibilityTest, InvalidAttributeAndUniformNames)
2125 {
2126     const std::string validAttribName =
2127         "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
2128     const std::string validUniformName =
2129         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
2130     std::vector<char> invalidSet = {'"', '$', '`', '@', '\''};
2131     if (getClientMajorVersion() < 3)
2132     {
2133         invalidSet.push_back('\\');
2134     }
2135 
2136     std::string vert = "attribute float ";
2137     vert += validAttribName;
2138     vert +=
2139         R"(;
2140 void main()
2141 {
2142     gl_Position = vec4(1.0);
2143 })";
2144 
2145     std::string frag =
2146         R"(precision highp float;
2147 uniform vec4 )";
2148     frag += validUniformName;
2149     // Insert illegal characters into comments
2150     frag +=
2151         R"(;
2152     // $ \" @ /*
2153 void main()
2154 {/*
2155     ` @ $
2156     */gl_FragColor = vec4(1.0);
2157 })";
2158 
2159     ANGLE_GL_PROGRAM(program, vert.c_str(), frag.c_str());
2160     EXPECT_GL_NO_ERROR();
2161 
2162     for (char invalidChar : invalidSet)
2163     {
2164         std::string invalidName = validAttribName + invalidChar;
2165         glGetAttribLocation(program, invalidName.c_str());
2166         EXPECT_GL_ERROR(GL_INVALID_VALUE)
2167             << "glGetAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
2168 
2169         glBindAttribLocation(program, 0, invalidName.c_str());
2170         EXPECT_GL_ERROR(GL_INVALID_VALUE)
2171             << "glBindAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
2172     }
2173 
2174     for (char invalidChar : invalidSet)
2175     {
2176         std::string invalidName = validUniformName + invalidChar;
2177         glGetUniformLocation(program, invalidName.c_str());
2178         EXPECT_GL_ERROR(GL_INVALID_VALUE)
2179             << "glGetUniformLocation unexpectedly succeeded for name \"" << invalidName << "\".";
2180     }
2181 
2182     for (char invalidChar : invalidSet)
2183     {
2184         std::string invalidAttribName = validAttribName + invalidChar;
2185         std::string invalidVert       = "attribute float ";
2186         invalidVert += invalidAttribName;
2187         invalidVert += R"(;,
2188 void main(),
2189 {,
2190     gl_Position = vec4(1.0);,
2191 })";
2192         GLuint program_number = CompileProgram(invalidVert.c_str(), essl1_shaders::fs::Red());
2193         EXPECT_EQ(0u, program_number);
2194     }
2195 }
2196 
2197 // Test that line continuation is handled correctly when validating shader source
TEST_P(WebGLCompatibilityTest,ShaderSourceLineContinuation)2198 TEST_P(WebGLCompatibilityTest, ShaderSourceLineContinuation)
2199 {
2200     // With recent changes to WebGL's shader source validation in
2201     // https://github.com/KhronosGroup/WebGL/pull/3206 and follow-ons,
2202     // the backslash character can be used in both WebGL 1.0 and 2.0
2203     // contexts.
2204 
2205     const char *validVert =
2206         R"(#define foo this \
2207     is a test
2208 precision mediump float;
2209 void main()
2210 {
2211     gl_Position = vec4(1.0);
2212 })";
2213 
2214     GLuint program = CompileProgram(validVert, essl1_shaders::fs::Red());
2215     EXPECT_NE(0u, program);
2216     glDeleteProgram(program);
2217 }
2218 
2219 // Test that line continuation is handled correctly when valdiating shader source
TEST_P(WebGL2CompatibilityTest,ShaderSourceLineContinuation)2220 TEST_P(WebGL2CompatibilityTest, ShaderSourceLineContinuation)
2221 {
2222     const char *validVert =
2223         R"(#version 300 es
2224 precision mediump float;
2225 
2226 void main ()
2227 {
2228     float f\
2229 oo = 1.0;
2230     gl_Position = vec4(foo);
2231 })";
2232 
2233     const char *invalidVert =
2234         R"(#version 300 es
2235 precision mediump float;
2236 
2237 void main ()
2238 {
2239     float f\$
2240 oo = 1.0;
2241     gl_Position = vec4(foo);
2242 })";
2243 
2244     GLuint program = CompileProgram(validVert, essl3_shaders::fs::Red());
2245     EXPECT_NE(0u, program);
2246     glDeleteProgram(program);
2247 
2248     program = CompileProgram(invalidVert, essl3_shaders::fs::Red());
2249     EXPECT_EQ(0u, program);
2250 }
2251 
2252 // Tests bindAttribLocations for reserved prefixes and length limits
TEST_P(WebGLCompatibilityTest,BindAttribLocationLimitation)2253 TEST_P(WebGLCompatibilityTest, BindAttribLocationLimitation)
2254 {
2255     constexpr int maxLocStringLength = 256;
2256     const std::string tooLongString(maxLocStringLength + 1, '_');
2257 
2258     glBindAttribLocation(0, 0, "_webgl_var");
2259 
2260     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2261 
2262     glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
2263 
2264     EXPECT_GL_ERROR(GL_INVALID_VALUE);
2265 }
2266 
2267 // Tests getAttribLocation for reserved prefixes
TEST_P(WebGLCompatibilityTest,GetAttribLocationNameLimitation)2268 TEST_P(WebGLCompatibilityTest, GetAttribLocationNameLimitation)
2269 {
2270     GLint attrLocation;
2271 
2272     attrLocation = glGetAttribLocation(0, "gl_attr");
2273     EXPECT_GL_NO_ERROR();
2274     EXPECT_EQ(-1, attrLocation);
2275 
2276     attrLocation = glGetAttribLocation(0, "webgl_attr");
2277     EXPECT_GL_NO_ERROR();
2278     EXPECT_EQ(-1, attrLocation);
2279 
2280     attrLocation = glGetAttribLocation(0, "_webgl_attr");
2281     EXPECT_GL_NO_ERROR();
2282     EXPECT_EQ(-1, attrLocation);
2283 }
2284 
2285 // Tests getAttribLocation for length limits
TEST_P(WebGLCompatibilityTest,GetAttribLocationLengthLimitation)2286 TEST_P(WebGLCompatibilityTest, GetAttribLocationLengthLimitation)
2287 {
2288     constexpr int maxLocStringLength = 256;
2289     const std::string tooLongString(maxLocStringLength + 1, '_');
2290 
2291     glGetAttribLocation(0, static_cast<const GLchar *>(tooLongString.c_str()));
2292 
2293     EXPECT_GL_ERROR(GL_INVALID_VALUE);
2294 }
2295 
2296 // Test that having no attributes with a zero divisor is valid in WebGL2
TEST_P(WebGL2CompatibilityTest,InstancedDrawZeroDivisor)2297 TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
2298 {
2299     constexpr char kVS[] =
2300         R"(attribute float a_pos;
2301 void main()
2302 {
2303     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
2304 })";
2305 
2306     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
2307 
2308     GLint posLocation = glGetAttribLocation(program, "a_pos");
2309     ASSERT_NE(-1, posLocation);
2310 
2311     glUseProgram(program);
2312 
2313     GLBuffer buffer;
2314     glBindBuffer(GL_ARRAY_BUFFER, buffer);
2315     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
2316 
2317     glEnableVertexAttribArray(posLocation);
2318     glVertexAttribDivisor(posLocation, 1);
2319 
2320     glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
2321     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
2322     ASSERT_GL_NO_ERROR();
2323 }
2324 
2325 // Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
TEST_P(WebGLCompatibilityTest,NPOT)2326 TEST_P(WebGLCompatibilityTest, NPOT)
2327 {
2328     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_texture_npot"));
2329 
2330     // Create a texture and set an NPOT mip 0, should always be acceptable.
2331     GLTexture texture;
2332     glBindTexture(GL_TEXTURE_2D, texture);
2333     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2334     ASSERT_GL_NO_ERROR();
2335 
2336     // Try setting an NPOT mip 1 and verify the error if WebGL 1
2337     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2338     if (getClientMajorVersion() < 3)
2339     {
2340         ASSERT_GL_ERROR(GL_INVALID_VALUE);
2341     }
2342     else
2343     {
2344         ASSERT_GL_NO_ERROR();
2345     }
2346 
2347     if (IsGLExtensionRequestable("GL_OES_texture_npot"))
2348     {
2349         glRequestExtensionANGLE("GL_OES_texture_npot");
2350         ASSERT_GL_NO_ERROR();
2351 
2352         // Try again to set NPOT mip 1
2353         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2354         ASSERT_GL_NO_ERROR();
2355     }
2356 }
2357 
2358 template <typename T>
FillTexture2D(GLuint texture,GLsizei width,GLsizei height,const T & onePixelData,GLint level,GLint internalFormat,GLenum format,GLenum type)2359 void FillTexture2D(GLuint texture,
2360                    GLsizei width,
2361                    GLsizei height,
2362                    const T &onePixelData,
2363                    GLint level,
2364                    GLint internalFormat,
2365                    GLenum format,
2366                    GLenum type)
2367 {
2368     std::vector<T> allPixelsData(width * height, onePixelData);
2369 
2370     glBindTexture(GL_TEXTURE_2D, texture);
2371     glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
2372                  allPixelsData.data());
2373     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2374     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2375     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2376     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2377 }
2378 
2379 // Test that unset gl_Position defaults to (0,0,0,0).
TEST_P(WebGLCompatibilityTest,DefaultPosition)2380 TEST_P(WebGLCompatibilityTest, DefaultPosition)
2381 {
2382     // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
2383     // and green otherwise.  The center of each quadrant will be red if and only if all
2384     // four corners are red.
2385     constexpr char kVS[] =
2386         R"(attribute vec3 pos;
2387 varying vec4 color;
2388 void main() {
2389     if (gl_Position == vec4(0,0,0,0)) {
2390         color = vec4(1,0,0,1);
2391     } else {
2392         color = vec4(0,1,0,1);
2393     }
2394     gl_Position = vec4(pos,1);
2395 })";
2396 
2397     constexpr char kFS[] =
2398         R"(precision mediump float;
2399 varying vec4 color;
2400 void main() {
2401     gl_FragColor = color;
2402 })";
2403 
2404     ANGLE_GL_PROGRAM(program, kVS, kFS);
2405     drawQuad(program, "pos", 0.0f, 1.0f, true);
2406     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
2407     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
2408     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
2409     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
2410 }
2411 
2412 // Tests that a rendering feedback loop triggers a GL error under WebGL.
2413 // Based on WebGL test conformance/renderbuffers/feedback-loop.html.
TEST_P(WebGLCompatibilityTest,RenderingFeedbackLoop)2414 TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
2415 {
2416     constexpr char kVS[] =
2417         R"(attribute vec4 a_position;
2418 varying vec2 v_texCoord;
2419 void main() {
2420     gl_Position = a_position;
2421     v_texCoord = (a_position.xy * 0.5) + 0.5;
2422 })";
2423 
2424     constexpr char kFS[] =
2425         R"(precision mediump float;
2426 varying vec2 v_texCoord;
2427 uniform sampler2D u_texture;
2428 void main() {
2429     // Shader swizzles color channels so we can tell if the draw succeeded.
2430     gl_FragColor = texture2D(u_texture, v_texCoord).gbra;
2431 })";
2432 
2433     GLTexture texture;
2434     FillTexture2D(texture, 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2435 
2436     ASSERT_GL_NO_ERROR();
2437 
2438     GLFramebuffer framebuffer;
2439     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2440     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2441 
2442     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2443 
2444     ANGLE_GL_PROGRAM(program, kVS, kFS);
2445 
2446     GLint uniformLoc = glGetUniformLocation(program, "u_texture");
2447     ASSERT_NE(-1, uniformLoc);
2448 
2449     glUseProgram(program);
2450     glUniform1i(uniformLoc, 0);
2451     glDisable(GL_BLEND);
2452     glDisable(GL_DEPTH_TEST);
2453     ASSERT_GL_NO_ERROR();
2454 
2455     // Drawing with a texture that is also bound to the current framebuffer should fail
2456     glBindTexture(GL_TEXTURE_2D, texture);
2457     drawQuad(program, "a_position", 0.5f, 1.0f, true);
2458     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2459 
2460     // Ensure that the texture contents did not change after the previous render
2461     glBindFramebuffer(GL_FRAMEBUFFER, 0);
2462     drawQuad(program, "a_position", 0.5f, 1.0f, true);
2463     ASSERT_GL_NO_ERROR();
2464     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
2465 
2466     // Drawing when texture is bound to an inactive uniform should succeed
2467     GLTexture texture2;
2468     FillTexture2D(texture2, 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2469 
2470     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2471     glActiveTexture(GL_TEXTURE1);
2472     glBindTexture(GL_TEXTURE_2D, texture);
2473     drawQuad(program, "a_position", 0.5f, 1.0f, true);
2474     ASSERT_GL_NO_ERROR();
2475     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2476 }
2477 
2478 // Multi-context uses of textures should not cause rendering feedback loops.
TEST_P(WebGLCompatibilityTest,MultiContextNoRenderingFeedbackLoops)2479 TEST_P(WebGLCompatibilityTest, MultiContextNoRenderingFeedbackLoops)
2480 {
2481     constexpr char kUnusedTextureVS[] =
2482         R"(attribute vec4 a_position;
2483 varying vec2 v_texCoord;
2484 void main() {
2485     gl_Position = a_position;
2486     v_texCoord = (a_position.xy * 0.5) + 0.5;
2487 })";
2488 
2489     constexpr char kUnusedTextureFS[] =
2490         R"(precision mediump float;
2491 varying vec2 v_texCoord;
2492 uniform sampler2D u_texture;
2493 void main() {
2494     gl_FragColor = texture2D(u_texture, v_texCoord).rgba;
2495 })";
2496 
2497     ANGLE_GL_PROGRAM(unusedProgram, kUnusedTextureVS, kUnusedTextureFS);
2498 
2499     glUseProgram(unusedProgram);
2500     GLint uniformLoc = glGetUniformLocation(unusedProgram, "u_texture");
2501     ASSERT_NE(-1, uniformLoc);
2502     glUniform1i(uniformLoc, 0);
2503 
2504     GLTexture texture;
2505     FillTexture2D(texture, 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2506     glBindTexture(GL_TEXTURE_2D, texture);
2507     // Note that _texture_ is still bound to GL_TEXTURE_2D in this context at this point.
2508 
2509     EGLWindow *window          = getEGLWindow();
2510     EGLDisplay display         = window->getDisplay();
2511     EGLConfig config           = window->getConfig();
2512     EGLSurface surface         = window->getSurface();
2513     EGLint contextAttributes[] = {
2514         EGL_CONTEXT_MAJOR_VERSION_KHR,
2515         GetParam().majorVersion,
2516         EGL_CONTEXT_MINOR_VERSION_KHR,
2517         GetParam().minorVersion,
2518         EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE,
2519         EGL_TRUE,
2520         EGL_NONE,
2521     };
2522     auto context1 = eglGetCurrentContext();
2523     // Create context2, sharing resources with context1.
2524     auto context2 = eglCreateContext(display, config, context1, contextAttributes);
2525     ASSERT_NE(context2, EGL_NO_CONTEXT);
2526     eglMakeCurrent(display, surface, surface, context2);
2527 
2528     constexpr char kVS[] =
2529         R"(attribute vec4 a_position;
2530 void main() {
2531     gl_Position = a_position;
2532 })";
2533 
2534     constexpr char kFS[] =
2535         R"(precision mediump float;
2536 void main() {
2537     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
2538 })";
2539 
2540     ANGLE_GL_PROGRAM(program, kVS, kFS);
2541     glUseProgram(program);
2542 
2543     ASSERT_GL_NO_ERROR();
2544 
2545     // Render to the texture in context2.
2546     GLFramebuffer framebuffer;
2547     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2548     // Texture is still a valid name in context2.
2549     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2550     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2551     // There is no rendering feedback loop at this point.
2552 
2553     glDisable(GL_BLEND);
2554     glDisable(GL_DEPTH_TEST);
2555     ASSERT_GL_NO_ERROR();
2556 
2557     drawQuad(program, "a_position", 0.5f, 1.0f, true);
2558     ASSERT_GL_NO_ERROR();
2559     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
2560 
2561     eglMakeCurrent(display, surface, surface, context1);
2562     eglDestroyContext(display, context2);
2563 }
2564 
2565 // Test for the max draw buffers and color attachments.
TEST_P(WebGLCompatibilityTest,MaxDrawBuffersAttachmentPoints)2566 TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
2567 {
2568     // This test only applies to ES2.
2569     if (getClientMajorVersion() != 2)
2570     {
2571         return;
2572     }
2573 
2574     GLFramebuffer fbo[2];
2575     glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
2576 
2577     // Test that is valid when we bind with a single attachment point.
2578     GLTexture texture;
2579     glBindTexture(GL_TEXTURE_2D, texture);
2580     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2581     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2582     ASSERT_GL_NO_ERROR();
2583 
2584     // Test that enabling the draw buffers extension will allow us to bind with a non-zero
2585     // attachment point.
2586     if (IsGLExtensionRequestable("GL_EXT_draw_buffers"))
2587     {
2588         glRequestExtensionANGLE("GL_EXT_draw_buffers");
2589         EXPECT_GL_NO_ERROR();
2590         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_draw_buffers"));
2591 
2592         glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
2593 
2594         GLTexture texture2;
2595         glBindTexture(GL_TEXTURE_2D, texture2);
2596         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2597         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
2598         ASSERT_GL_NO_ERROR();
2599     }
2600 }
2601 
2602 // Test that the offset in the index buffer is forced to be a multiple of the element size
TEST_P(WebGLCompatibilityTest,DrawElementsOffsetRestriction)2603 TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
2604 {
2605     constexpr char kVS[] =
2606         R"(attribute vec3 a_pos;
2607 void main()
2608 {
2609     gl_Position = vec4(a_pos, 1.0);
2610 })";
2611 
2612     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
2613 
2614     GLint posLocation = glGetAttribLocation(program, "a_pos");
2615     ASSERT_NE(-1, posLocation);
2616     glUseProgram(program);
2617 
2618     const auto &vertices = GetQuadVertices();
2619 
2620     GLBuffer vertexBuffer;
2621     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
2622     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
2623                  GL_STATIC_DRAW);
2624 
2625     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2626     glEnableVertexAttribArray(posLocation);
2627 
2628     GLBuffer indexBuffer;
2629     const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0, 0};
2630     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
2631     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2632 
2633     ASSERT_GL_NO_ERROR();
2634 
2635     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
2636     ASSERT_GL_NO_ERROR();
2637 
2638     glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, nullptr);
2639     ASSERT_GL_NO_ERROR();
2640 
2641     glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(1));
2642     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2643 }
2644 
2645 // Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
2646 // size
TEST_P(WebGLCompatibilityTest,VertexAttribPointerOffsetRestriction)2647 TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
2648 {
2649     // Base case, vector of two floats
2650     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
2651     ASSERT_GL_NO_ERROR();
2652 
2653     // Test setting a non-multiple offset
2654     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const void *>(1));
2655     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2656     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const void *>(2));
2657     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2658     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const void *>(3));
2659     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2660 
2661     // Test setting a non-multiple stride
2662     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, nullptr);
2663     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2664     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, nullptr);
2665     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2666     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, nullptr);
2667     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2668 }
2669 
drawBuffersEXTFeedbackLoop(GLuint program,const std::array<GLenum,2> & drawBuffers,GLenum expectedError)2670 void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
2671                                                         const std::array<GLenum, 2> &drawBuffers,
2672                                                         GLenum expectedError)
2673 {
2674     glDrawBuffersEXT(2, drawBuffers.data());
2675 
2676     // Make sure framebuffer is complete before feedback loop detection
2677     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2678 
2679     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2680 
2681     // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2682     // it should be NO_ERROR"
2683     EXPECT_GL_ERROR(expectedError);
2684 }
2685 
2686 // This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
2687 // Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
TEST_P(WebGLCompatibilityTest,RenderingFeedbackLoopWithDrawBuffersEXT)2688 TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
2689 {
2690     constexpr char kVS[] =
2691         R"(attribute vec4 aPosition;
2692 varying vec2 texCoord;
2693 void main() {
2694     gl_Position = aPosition;
2695     texCoord = (aPosition.xy * 0.5) + 0.5;
2696 })";
2697 
2698     constexpr char kFS[] =
2699         R"(#extension GL_EXT_draw_buffers : require
2700 precision mediump float;
2701 uniform sampler2D tex;
2702 varying vec2 texCoord;
2703 void main() {
2704     gl_FragData[0] = texture2D(tex, texCoord);
2705     gl_FragData[1] = texture2D(tex, texCoord);
2706 })";
2707 
2708     GLsizei width  = 8;
2709     GLsizei height = 8;
2710 
2711     // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
2712     // extension and gl_FragData semantics are changed to enforce indexing by zero always.
2713     // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
2714     if (/*!IsGLExtensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
2715     {
2716         // No WEBGL_draw_buffers support -- this is legal.
2717         return;
2718     }
2719 
2720     GLint maxDrawBuffers = 0;
2721     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2722 
2723     // Test skipped because MAX_DRAW_BUFFERS is too small.
2724     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 2);
2725 
2726     ANGLE_GL_PROGRAM(program, kVS, kFS);
2727     glUseProgram(program);
2728     glViewport(0, 0, width, height);
2729 
2730     GLTexture tex0;
2731     GLTexture tex1;
2732     GLFramebuffer fbo;
2733     FillTexture2D(tex0, width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2734     FillTexture2D(tex1, width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2735     ASSERT_GL_NO_ERROR();
2736 
2737     glBindTexture(GL_TEXTURE_2D, tex1);
2738     GLint texLoc = glGetUniformLocation(program, "tex");
2739     ASSERT_NE(-1, texLoc);
2740     glUniform1i(texLoc, 0);
2741     ASSERT_GL_NO_ERROR();
2742 
2743     // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2744     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2745     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0);
2746     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1, 0);
2747 
2748     drawBuffersEXTFeedbackLoop(program, {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
2749     drawBuffersEXTFeedbackLoop(program, {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2750                                GL_INVALID_OPERATION);
2751     // A feedback loop is formed regardless of drawBuffers settings.
2752     drawBuffersEXTFeedbackLoop(program, {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_INVALID_OPERATION);
2753 }
2754 
2755 // Test tests that texture copying feedback loops are properly rejected in WebGL.
2756 // Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
TEST_P(WebGLCompatibilityTest,TextureCopyingFeedbackLoops)2757 TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
2758 {
2759     // TODO(anglebug.com/40096747): Failing on ARM-based Apple DTKs.
2760     ANGLE_SKIP_TEST_IF(IsMac() && IsARM64() && IsDesktopOpenGL());
2761 
2762     GLTexture texture;
2763     glBindTexture(GL_TEXTURE_2D, texture);
2764     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2765     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2766     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2767     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2768     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2769 
2770     GLTexture texture2;
2771     glBindTexture(GL_TEXTURE_2D, texture2);
2772     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2773     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2774     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2775     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2776     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2777 
2778     GLFramebuffer framebuffer;
2779     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2780     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2781 
2782     // framebuffer should be FRAMEBUFFER_COMPLETE.
2783     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2784     ASSERT_GL_NO_ERROR();
2785 
2786     // testing copyTexImage2D
2787 
2788     // copyTexImage2D to same texture but different level
2789     glBindTexture(GL_TEXTURE_2D, texture);
2790     glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
2791     EXPECT_GL_NO_ERROR();
2792 
2793     // copyTexImage2D to same texture same level, invalid feedback loop
2794     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2795     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2796 
2797     // copyTexImage2D to different texture
2798     glBindTexture(GL_TEXTURE_2D, texture2);
2799     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2800     EXPECT_GL_NO_ERROR();
2801 
2802     // testing copyTexSubImage2D
2803 
2804     // copyTexSubImage2D to same texture but different level
2805     glBindTexture(GL_TEXTURE_2D, texture);
2806     glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
2807     EXPECT_GL_NO_ERROR();
2808 
2809     // copyTexSubImage2D to same texture same level, invalid feedback loop
2810     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2811     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2812 
2813     // copyTexSubImage2D to different texture
2814     glBindTexture(GL_TEXTURE_2D, texture2);
2815     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2816     EXPECT_GL_NO_ERROR();
2817 }
2818 
2819 // Test that copying from mip 1 of a texture to mip 0 works.  When the framebuffer is attached to
2820 // mip 1 of a mip-complete texture, an image with both mips are created.  When copying from the
2821 // framebuffer to mip 0, it is being redefined.
TEST_P(WebGL2CompatibilityTest,CopyMip1ToMip0)2822 TEST_P(WebGL2CompatibilityTest, CopyMip1ToMip0)
2823 {
2824     // http://anglebug.com/42263391
2825     ANGLE_SKIP_TEST_IF(IsD3D11());
2826 
2827     // http://anglebug.com/42263392
2828     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && (IsWindows() || IsMac()));
2829 
2830     // TODO(anglebug.com/40096747): Failing on ARM64-based Apple DTKs.
2831     ANGLE_SKIP_TEST_IF(IsMac() && IsARM64() && IsDesktopOpenGL());
2832 
2833     GLFramebuffer framebuffer;
2834     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2835 
2836     GLTexture texture;
2837     glBindTexture(GL_TEXTURE_2D, texture);
2838 
2839     const GLColor mip0[4] = {
2840         GLColor::red,
2841         GLColor::red,
2842         GLColor::red,
2843         GLColor::red,
2844     };
2845     const GLColor mip1[1] = {
2846         GLColor::green,
2847     };
2848 
2849     // Create a complete mip chain in mips 0 to 2
2850     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip0);
2851     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip1);
2852 
2853     // Framebuffer can bind to mip 1, as the texture is mip-complete.
2854     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
2855     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2856 
2857     // Copy to mip 0.  This shouldn't crash.
2858     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
2859     EXPECT_GL_NO_ERROR();
2860 
2861     // The framebuffer is now incomplete.
2862     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
2863                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
2864 
2865     // http://anglebug.com/42263389
2866     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA());
2867 
2868     // http://anglebug.com/42263390
2869     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsMac());
2870 
2871     // Bind framebuffer to mip 0 and make sure the copy was done.
2872     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
2873     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2874     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2875 
2876     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
2877 }
2878 
2879 // Test that copying from mip 0 of a texture to mip 1 works.  When the framebuffer is attached to
2880 // mip 0 of a mip-complete texture, an image with both mips are created.  When copying from the
2881 // framebuffer to mip 1, it is being redefined.
TEST_P(WebGL2CompatibilityTest,CopyMip0ToMip1)2882 TEST_P(WebGL2CompatibilityTest, CopyMip0ToMip1)
2883 {
2884     // http://anglebug.com/42263392
2885     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
2886 
2887     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsWindows());
2888 
2889     GLFramebuffer framebuffer;
2890     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2891 
2892     GLTexture texture;
2893     glBindTexture(GL_TEXTURE_2D, texture);
2894 
2895     const GLColor mip0[4] = {
2896         GLColor::red,
2897         GLColor::red,
2898         GLColor::red,
2899         GLColor::red,
2900     };
2901     const GLColor mip1[1] = {
2902         GLColor::green,
2903     };
2904 
2905     // Create a complete mip chain in mips 0 to 2
2906     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip0);
2907     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip1);
2908 
2909     // Framebuffer can bind to mip 0, as the texture is mip-complete.
2910     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2911     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2912 
2913     // Copy to mip 1.  This shouldn't crash.
2914     glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
2915     EXPECT_GL_NO_ERROR();
2916 
2917     // The framebuffer is still complete.
2918     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2919     // Make sure mip 0 is untouched.
2920     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2921     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
2922 
2923     // Bind framebuffer to mip 1 and make sure the copy was done.
2924     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
2925     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
2926     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2927 
2928     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2929     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
2930 }
2931 
drawBuffersFeedbackLoop(GLuint program,const std::array<GLenum,2> & drawBuffers,GLenum expectedError)2932 void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
2933                                                      const std::array<GLenum, 2> &drawBuffers,
2934                                                      GLenum expectedError)
2935 {
2936     glDrawBuffers(2, drawBuffers.data());
2937 
2938     // Make sure framebuffer is complete before feedback loop detection
2939     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2940 
2941     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2942 
2943     // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2944     // it should be NO_ERROR"
2945     EXPECT_GL_ERROR(expectedError);
2946 }
2947 
2948 // Tests invariance matching rules between built in varyings.
2949 // Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
TEST_P(WebGLCompatibilityTest,BuiltInInvariant)2950 TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
2951 {
2952     constexpr char kVS[] =
2953         R"(varying vec4 v_varying;
2954 void main()
2955 {
2956     gl_PointSize = 1.0;
2957     gl_Position = v_varying;
2958 })";
2959     constexpr char kFSInvariantGlFragCoord[] =
2960         R"(invariant gl_FragCoord;
2961 void main()
2962 {
2963     gl_FragColor = gl_FragCoord;
2964 })";
2965     constexpr char kFSInvariantGlPointCoord[] =
2966         R"(invariant gl_PointCoord;
2967 void main()
2968 {
2969     gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);
2970 })";
2971 
2972     GLuint program = CompileProgram(kVS, kFSInvariantGlFragCoord);
2973     EXPECT_EQ(0u, program);
2974 
2975     program = CompileProgram(kVS, kFSInvariantGlPointCoord);
2976     EXPECT_EQ(0u, program);
2977 }
2978 
2979 // Tests global namespace conflicts between uniforms and attributes.
2980 // Based on WebGL test conformance/glsl/misc/shaders-with-name-conflicts.html.
TEST_P(WebGLCompatibilityTest,GlobalNamesConflict)2981 TEST_P(WebGLCompatibilityTest, GlobalNamesConflict)
2982 {
2983     constexpr char kVS[] =
2984         R"(attribute vec4 foo;
2985 void main()
2986 {
2987     gl_Position = foo;
2988 })";
2989     constexpr char kFS[] =
2990         R"(precision mediump float;
2991 uniform vec4 foo;
2992 void main()
2993 {
2994     gl_FragColor = foo;
2995 })";
2996 
2997     GLuint program = CompileProgram(kVS, kFS);
2998     EXPECT_NE(0u, program);
2999 }
3000 
3001 // Test dimension and image size validation of compressed textures
TEST_P(WebGLCompatibilityTest,CompressedTextureS3TC)3002 TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
3003 {
3004     if (IsGLExtensionRequestable("GL_EXT_texture_compression_dxt1"))
3005     {
3006         glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
3007     }
3008 
3009     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
3010 
3011     constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
3012 
3013     GLTexture texture;
3014     glBindTexture(GL_TEXTURE_2D, texture);
3015 
3016     // Regular case, verify that it works
3017     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3018                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3019     ASSERT_GL_NO_ERROR();
3020 
3021     // Test various dimensions that are not valid
3022     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
3023                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3024     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3025 
3026     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
3027                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3028     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3029 
3030     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
3031                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3032     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3033 
3034     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
3035                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3036     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3037 
3038     // Test various image sizes that are not valid
3039     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3040                            sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
3041     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3042 
3043     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3044                            sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
3045     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3046 
3047     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
3048                            CompressedImageDXT1);
3049     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3050 
3051     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
3052                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3053     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3054 
3055     // Fill a full mip chain and verify that it works
3056     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3057                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3058     glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
3059                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3060     glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
3061                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3062     ASSERT_GL_NO_ERROR();
3063 
3064     glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3065                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3066     ASSERT_GL_NO_ERROR();
3067 
3068     // Test that non-block size sub-uploads are not valid for the 0 mip
3069     glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3070                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3071     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3072 
3073     // Test that non-block size sub-uploads are valid for if they fill the whole mip
3074     glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3075                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3076     glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3077                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3078     ASSERT_GL_NO_ERROR();
3079 
3080     // Test that if the format miss-matches the texture, an error is generated
3081     glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
3082                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3083     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3084 }
3085 
3086 // Test WebGL-specific constraints on sizes of S3TC textures' mipmap levels.
TEST_P(WebGLCompatibilityTest,CompressedTexImageS3TC)3087 TEST_P(WebGLCompatibilityTest, CompressedTexImageS3TC)
3088 {
3089     const char *extensions[] = {
3090         "GL_EXT_texture_compression_dxt1",
3091         "GL_ANGLE_texture_compression_dxt3",
3092         "GL_ANGLE_texture_compression_dxt5",
3093     };
3094 
3095     for (const char *extension : extensions)
3096     {
3097         if (IsGLExtensionRequestable(extension))
3098         {
3099             glRequestExtensionANGLE(extension);
3100         }
3101 
3102         ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(extension));
3103     }
3104 
3105     // Ported from WebGL conformance suite:
3106     // sdk/tests/conformance/extensions/s3tc-and-srgb.html
3107     constexpr GLenum formats[] = {
3108         GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3109         GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
3110         GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
3111         GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
3112     };
3113 
3114     for (GLenum format : formats)
3115     {
3116         testCompressedTexImage(format);
3117     }
3118 }
3119 
3120 // Test WebGL-specific constraints on sizes of RGTC textures' mipmap levels.
TEST_P(WebGLCompatibilityTest,CompressedTexImageRGTC)3121 TEST_P(WebGLCompatibilityTest, CompressedTexImageRGTC)
3122 {
3123     if (IsGLExtensionRequestable("GL_EXT_texture_compression_rgtc"))
3124     {
3125         glRequestExtensionANGLE("GL_EXT_texture_compression_rgtc");
3126     }
3127 
3128     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_rgtc"));
3129 
3130     // Ported from WebGL conformance suite:
3131     // sdk/tests/conformance/extensions/ext-texture-compression-rgtc.html
3132     constexpr GLenum formats[] = {GL_COMPRESSED_RED_RGTC1_EXT, GL_COMPRESSED_SIGNED_RED_RGTC1_EXT,
3133                                   GL_COMPRESSED_RED_GREEN_RGTC2_EXT,
3134                                   GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT};
3135 
3136     for (GLenum format : formats)
3137     {
3138         testCompressedTexImage(format);
3139     }
3140 }
3141 
3142 // Test WebGL-specific constraints on sizes of BPTC textures' mipmap levels.
TEST_P(WebGLCompatibilityTest,CompressedTexImageBPTC)3143 TEST_P(WebGLCompatibilityTest, CompressedTexImageBPTC)
3144 {
3145     if (IsGLExtensionRequestable("GL_EXT_texture_compression_bptc"))
3146     {
3147         glRequestExtensionANGLE("GL_EXT_texture_compression_bptc");
3148     }
3149 
3150     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc"));
3151 
3152     // Ported from WebGL conformance suite:
3153     // sdk/tests/conformance/extensions/ext-texture-compression-bptc.html
3154     constexpr GLenum formats[] = {
3155         GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT,
3156         GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT};
3157 
3158     for (GLenum format : formats)
3159     {
3160         testCompressedTexImage(format);
3161     }
3162 }
3163 
TEST_P(WebGLCompatibilityTest,L32FTextures)3164 TEST_P(WebGLCompatibilityTest, L32FTextures)
3165 {
3166     constexpr float textureData[]   = {15.1f, 0.0f, 0.0f, 0.0f};
3167     constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
3168 
3169     for (auto extension : FloatingPointTextureExtensions)
3170     {
3171         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3172         {
3173             glRequestExtensionANGLE(extension);
3174             ASSERT_GL_NO_ERROR();
3175         }
3176 
3177         // Unsized L 32F
3178         {
3179             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3180             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3181             bool render  = false;
3182             TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
3183                                    textureData, readPixelData);
3184         }
3185 
3186         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3187         {
3188             // Sized L 32F
3189             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3190                            IsGLExtensionEnabled("GL_EXT_texture_storage");
3191             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3192             bool render = false;
3193             TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
3194                                    render, textureData, readPixelData);
3195         }
3196     }
3197 }
3198 
TEST_P(WebGLCompatibilityTest,A32FTextures)3199 TEST_P(WebGLCompatibilityTest, A32FTextures)
3200 {
3201     constexpr float textureData[]   = {33.33f, 0.0f, 0.0f, 0.0f};
3202     constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
3203 
3204     for (auto extension : FloatingPointTextureExtensions)
3205     {
3206         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3207         {
3208             glRequestExtensionANGLE(extension);
3209             ASSERT_GL_NO_ERROR();
3210         }
3211 
3212         // Unsized A 32F
3213         {
3214             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3215             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3216             bool render  = false;
3217             TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
3218                                    textureData, readPixelData);
3219         }
3220 
3221         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3222         {
3223             // Sized A 32F
3224             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3225                            IsGLExtensionEnabled("GL_EXT_texture_storage");
3226             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3227             bool render = false;
3228             TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
3229                                    textureData, readPixelData);
3230         }
3231     }
3232 }
3233 
TEST_P(WebGLCompatibilityTest,LA32FTextures)3234 TEST_P(WebGLCompatibilityTest, LA32FTextures)
3235 {
3236     constexpr float textureData[]   = {-0.21f, 15.1f, 0.0f, 0.0f};
3237     constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
3238                                        textureData[1]};
3239 
3240     for (auto extension : FloatingPointTextureExtensions)
3241     {
3242         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3243         {
3244             glRequestExtensionANGLE(extension);
3245             ASSERT_GL_NO_ERROR();
3246         }
3247 
3248         // Unsized LA 32F
3249         {
3250             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3251             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3252             bool render  = false;
3253             TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
3254                                    filter, render, textureData, readPixelData);
3255         }
3256 
3257         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3258         {
3259             // Sized LA 32F
3260             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3261                            IsGLExtensionEnabled("GL_EXT_texture_storage");
3262             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3263             bool render = false;
3264             TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
3265                                    filter, render, textureData, readPixelData);
3266         }
3267     }
3268 }
3269 
TEST_P(WebGLCompatibilityTest,R32FTextures)3270 TEST_P(WebGLCompatibilityTest, R32FTextures)
3271 {
3272     constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
3273 
3274     for (auto extension : FloatingPointTextureExtensions)
3275     {
3276         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3277         {
3278             glRequestExtensionANGLE(extension);
3279             ASSERT_GL_NO_ERROR();
3280         }
3281 
3282         // Unsized R 32F
3283         {
3284             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3285                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3286             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3287             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3288             TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
3289         }
3290 
3291         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3292         {
3293             // Sized R 32F
3294             bool texture =
3295                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3296                                                    IsGLExtensionEnabled("GL_EXT_texture_rg") &&
3297                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3298             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3299             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3300             TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
3301         }
3302     }
3303 }
3304 
TEST_P(WebGLCompatibilityTest,RG32FTextures)3305 TEST_P(WebGLCompatibilityTest, RG32FTextures)
3306 {
3307     constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
3308 
3309     for (auto extension : FloatingPointTextureExtensions)
3310     {
3311         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3312         {
3313             glRequestExtensionANGLE(extension);
3314             ASSERT_GL_NO_ERROR();
3315         }
3316 
3317         // Unsized RG 32F
3318         {
3319             bool texture = (IsGLExtensionEnabled("GL_OES_texture_float") &&
3320                             IsGLExtensionEnabled("GL_EXT_texture_rg"));
3321             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3322             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3323             TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
3324         }
3325 
3326         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3327         {
3328             // Sized RG 32F
3329             bool texture =
3330                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3331                                                    IsGLExtensionEnabled("GL_EXT_texture_rg") &&
3332                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3333             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3334             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3335             TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
3336         }
3337     }
3338 }
3339 
TEST_P(WebGLCompatibilityTest,RGB32FTextures)3340 TEST_P(WebGLCompatibilityTest, RGB32FTextures)
3341 {
3342     constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
3343 
3344     for (auto extension : FloatingPointTextureExtensions)
3345     {
3346         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3347         {
3348             glRequestExtensionANGLE(extension);
3349             ASSERT_GL_NO_ERROR();
3350         }
3351 
3352         // Unsized RGB 32F
3353         {
3354             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3355             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3356             bool render  = false;
3357             TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
3358         }
3359 
3360         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3361         {
3362             // Sized RGB 32F
3363             bool texture =
3364                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3365                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3366             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3367             bool render = IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
3368             TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
3369                                    data);
3370         }
3371     }
3372 }
3373 
TEST_P(WebGLCompatibilityTest,RGBA32FTextures)3374 TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
3375 {
3376     // http://anglebug.com/42263897
3377     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsMac());
3378 
3379     constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
3380 
3381     for (auto extension : FloatingPointTextureExtensions)
3382     {
3383         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3384         {
3385             glRequestExtensionANGLE(extension);
3386             ASSERT_GL_NO_ERROR();
3387         }
3388 
3389         // Unsized RGBA 32F
3390         {
3391             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3392             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3393             bool render  = false;
3394             TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
3395         }
3396 
3397         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3398         {
3399             // Sized RGBA 32F
3400             bool texture =
3401                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3402                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3403             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3404             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3405                           IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
3406             TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
3407                                    data);
3408         }
3409     }
3410 }
3411 
3412 // Test that has float color attachment caching works when color attachments change, by calling draw
3413 // command when blending is enabled
TEST_P(WebGLCompatibilityTest,FramebufferFloatColorAttachment)3414 TEST_P(WebGLCompatibilityTest, FramebufferFloatColorAttachment)
3415 {
3416     if (getClientMajorVersion() >= 3)
3417     {
3418         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3419     }
3420     else
3421     {
3422         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_float"));
3423         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
3424     }
3425 
3426     constexpr char kVS[] =
3427         R"(void main()
3428 {
3429     gl_Position = vec4(0, 0, 0, 1);
3430 })";
3431 
3432     constexpr char kFS[] =
3433         R"(void main()
3434 {
3435     gl_FragColor = vec4(0, 1, 0, 1);
3436 })";
3437 
3438     ANGLE_GL_PROGRAM(program, kVS, kFS);
3439     glUseProgram(program);
3440 
3441     glEnable(GL_BLEND);
3442 
3443     GLTexture texture1;
3444     glBindTexture(GL_TEXTURE_2D, texture1);
3445     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3446     EXPECT_GL_NO_ERROR();
3447 
3448     GLTexture texture2;
3449     glBindTexture(GL_TEXTURE_2D, texture2);
3450     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3451     EXPECT_GL_NO_ERROR();
3452 
3453     GLFramebuffer fbo1;
3454     glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
3455     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3456     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3457 
3458     GLFramebuffer fbo2;
3459     glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
3460     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
3461     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3462     glDrawArrays(GL_POINTS, 0, 1);
3463     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3464 
3465     glDisable(GL_BLEND);
3466     glDrawArrays(GL_POINTS, 0, 1);
3467     EXPECT_GL_NO_ERROR();
3468     glEnable(GL_BLEND);
3469 
3470     glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
3471     glDrawArrays(GL_POINTS, 0, 1);
3472 
3473     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0,
3474                            0);  // test unbind
3475     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
3476     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3477 
3478     glDrawArrays(GL_POINTS, 0, 1);
3479     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3480 
3481     glDisable(GL_BLEND);
3482     glDrawArrays(GL_POINTS, 0, 1);
3483     EXPECT_GL_NO_ERROR();
3484     glEnable(GL_BLEND);
3485 
3486     glBindTexture(GL_TEXTURE_2D, texture2);
3487     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3488 
3489     glDrawArrays(GL_POINTS, 0, 1);
3490     EXPECT_GL_NO_ERROR();
3491 }
3492 
3493 // Test that has float color attachment caching works with multiple color attachments bound to a
3494 // Framebuffer
TEST_P(WebGLCompatibilityTest,FramebufferFloatColorAttachmentMRT)3495 TEST_P(WebGLCompatibilityTest, FramebufferFloatColorAttachmentMRT)
3496 {
3497     bool isWebGL2 = getClientMajorVersion() >= 3;
3498     if (isWebGL2)
3499     {
3500         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3501 
3502         constexpr char kVS[] =
3503             R"(#version 300 es
3504 void main()
3505 {
3506     gl_Position = vec4(0, 0, 0, 1);
3507 })";
3508 
3509         constexpr char kFS[] =
3510             R"(#version 300 es
3511 precision lowp float;
3512 layout(location = 0) out vec4 o_color0;
3513 layout(location = 1) out vec4 o_color1;
3514 void main()
3515 {
3516     o_color0 = vec4(1, 0, 0, 1);
3517     o_color1 = vec4(0, 1, 0, 1);
3518 })";
3519 
3520         ANGLE_GL_PROGRAM(program, kVS, kFS);
3521         glUseProgram(program);
3522     }
3523     else
3524     {
3525         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_float"));
3526         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
3527         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_draw_buffers"));
3528 
3529         constexpr char kVS[] =
3530             R"(void main()
3531 {
3532     gl_Position = vec4(0, 0, 0, 1);
3533 })";
3534 
3535         constexpr char kFS[] =
3536             R"(#extension GL_EXT_draw_buffers : require
3537 precision lowp float;
3538 void main()
3539 {
3540     gl_FragData[0] = vec4(1, 0, 0, 1);
3541     gl_FragData[1] = vec4(0, 1, 0, 1);
3542 })";
3543 
3544         ANGLE_GL_PROGRAM(program, kVS, kFS);
3545         glUseProgram(program);
3546     }
3547 
3548     glEnable(GL_BLEND);
3549 
3550     GLTexture texture1;
3551     glBindTexture(GL_TEXTURE_2D, texture1);
3552     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3553     EXPECT_GL_NO_ERROR();
3554 
3555     GLTexture texture2;
3556     glBindTexture(GL_TEXTURE_2D, texture2);
3557     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3558     EXPECT_GL_NO_ERROR();
3559 
3560     GLTexture textureF1;
3561     glBindTexture(GL_TEXTURE_2D, textureF1);
3562     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3563     EXPECT_GL_NO_ERROR();
3564 
3565     GLTexture textureF2;
3566     glBindTexture(GL_TEXTURE_2D, textureF2);
3567     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3568     EXPECT_GL_NO_ERROR();
3569 
3570     GLFramebuffer fbo;
3571     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3572     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3573     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
3574     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3575 
3576     GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
3577     if (isWebGL2)
3578     {
3579         glDrawBuffers(2, drawbuffers);
3580     }
3581     else
3582     {
3583         glDrawBuffersEXT(2, drawbuffers);
3584     }
3585 
3586     glDrawArrays(GL_POINTS, 0, 1);
3587     EXPECT_GL_NO_ERROR();
3588 
3589     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureF1, 0);
3590     glDrawArrays(GL_POINTS, 0, 1);
3591     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3592 
3593     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textureF2, 0);
3594     glDrawArrays(GL_POINTS, 0, 1);
3595     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3596 
3597     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3598     glDrawArrays(GL_POINTS, 0, 1);
3599     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3600 
3601     if (isWebGL2)
3602     {
3603         // WebGL 1 will report a FRAMEBUFFER_UNSUPPORTED for one unsigned_byte and one float
3604         // attachment bound to one FBO at the same time
3605         glDrawBuffers(1, drawbuffers);
3606         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3607         glDrawArrays(GL_POINTS, 0, 1);
3608         EXPECT_GL_NO_ERROR();
3609         glDrawBuffers(2, drawbuffers);
3610     }
3611 
3612     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
3613     glDrawArrays(GL_POINTS, 0, 1);
3614     EXPECT_GL_NO_ERROR();
3615 }
3616 
TestBlendColor(const bool shouldClamp)3617 static void TestBlendColor(const bool shouldClamp)
3618 {
3619     auto expected = GLColor32F(5, 0, 0, 0);
3620     glBlendColor(expected.R, expected.G, expected.B, expected.A);
3621     if (shouldClamp)
3622     {
3623         expected.R = 1;
3624     }
3625 
3626     float arr[4] = {};
3627     glGetFloatv(GL_BLEND_COLOR, arr);
3628     const auto actual = GLColor32F(arr[0], arr[1], arr[2], arr[3]);
3629     EXPECT_COLOR_NEAR(expected, actual, 0.001);
3630 }
3631 
3632 // Test if blending of float32 color attachment generates GL_INVALID_OPERATION when
3633 // GL_EXT_float_blend is not enabled
TEST_P(WebGLCompatibilityTest,FloatBlend)3634 TEST_P(WebGLCompatibilityTest, FloatBlend)
3635 {
3636     if (getClientMajorVersion() >= 3)
3637     {
3638         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3639     }
3640     else
3641     {
3642         TestBlendColor(true);
3643         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_float"));
3644         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
3645     }
3646 
3647     // -
3648 
3649     TestExtFloatBlend(GL_RGBA32F, GL_FLOAT, false);
3650 
3651     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_float_blend"));
3652     ASSERT_GL_NO_ERROR();
3653 
3654     TestExtFloatBlend(GL_RGBA32F, GL_FLOAT, true);
3655 }
3656 
3657 // Test the blending of float16 color attachments
TEST_P(WebGLCompatibilityTest,HalfFloatBlend)3658 TEST_P(WebGLCompatibilityTest, HalfFloatBlend)
3659 {
3660     GLenum internalFormat = GL_RGBA16F;
3661     GLenum type           = GL_FLOAT;
3662     if (getClientMajorVersion() >= 3)
3663     {
3664         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3665     }
3666     else
3667     {
3668         TestBlendColor(true);
3669         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_half_float"));
3670         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_half_float"));
3671         internalFormat = GL_RGBA;
3672         type           = GL_HALF_FLOAT_OES;
3673     }
3674 
3675     // -
3676 
3677     TestExtFloatBlend(internalFormat, type, true);
3678 }
3679 
TEST_P(WebGLCompatibilityTest,R16FTextures)3680 TEST_P(WebGLCompatibilityTest, R16FTextures)
3681 {
3682     // http://anglebug.com/42263897
3683     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsMac());
3684 
3685     constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
3686     const GLushort textureData[]     = {
3687         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3688         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3689 
3690     for (auto extension : FloatingPointTextureExtensions)
3691     {
3692         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3693         {
3694             glRequestExtensionANGLE(extension);
3695             ASSERT_GL_NO_ERROR();
3696         }
3697 
3698         // Unsized R 16F (OES)
3699         if (getClientMajorVersion() < 3)
3700         {
3701             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3702                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3703             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3704             bool render = false;
3705             TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
3706                                    textureData, readPixelsData);
3707         }
3708 
3709         // Unsized R 16F
3710         {
3711             bool texture = false;
3712             bool filter  = false;
3713             bool render  = false;
3714             TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
3715                                    textureData, readPixelsData);
3716         }
3717 
3718         if (getClientMajorVersion() >= 3)
3719         {
3720             // Sized R 16F
3721             bool texture = true;
3722             bool filter  = true;
3723             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3724                           IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3725             TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
3726                                    textureData, readPixelsData);
3727         }
3728         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3729         {
3730             // Sized R 16F (OES)
3731             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3732                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3733             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3734             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3735             TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
3736                                    textureData, readPixelsData);
3737         }
3738     }
3739 }
3740 
TEST_P(WebGLCompatibilityTest,RG16FTextures)3741 TEST_P(WebGLCompatibilityTest, RG16FTextures)
3742 {
3743     // http://anglebug.com/42263897
3744     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsMac());
3745 
3746     constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
3747     const GLushort textureData[]     = {
3748         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3749         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3750 
3751     for (auto extension : FloatingPointTextureExtensions)
3752     {
3753         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3754         {
3755             glRequestExtensionANGLE(extension);
3756             ASSERT_GL_NO_ERROR();
3757         }
3758 
3759         // Unsized RG 16F (OES)
3760         if (getClientMajorVersion() < 3)
3761         {
3762             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3763                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3764             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3765             bool render = false;
3766             TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
3767                                    textureData, readPixelsData);
3768         }
3769 
3770         // Unsized RG 16F
3771         {
3772             bool texture = false;
3773             bool filter  = false;
3774             bool render  = false;
3775             TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
3776                                    textureData, readPixelsData);
3777         }
3778 
3779         if (getClientMajorVersion() >= 3)
3780         {
3781             // Sized RG 16F
3782             bool texture = true;
3783             bool filter  = true;
3784             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3785                           IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3786             TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
3787                                    textureData, readPixelsData);
3788         }
3789         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3790         {
3791             // Sized RG 16F (OES)
3792             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3793                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3794             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3795             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3796             TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
3797                                    textureData, readPixelsData);
3798         }
3799     }
3800 }
3801 
TEST_P(WebGLCompatibilityTest,RGB16FTextures)3802 TEST_P(WebGLCompatibilityTest, RGB16FTextures)
3803 {
3804     // http://anglebug.com/42263897
3805     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsMac());
3806 
3807     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
3808 
3809     constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
3810     const GLushort textureData[]     = {
3811         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3812         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3813 
3814     for (auto extension : FloatingPointTextureExtensions)
3815     {
3816         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3817         {
3818             glRequestExtensionANGLE(extension);
3819             ASSERT_GL_NO_ERROR();
3820         }
3821 
3822         // Unsized RGB 16F (OES)
3823         if (getClientMajorVersion() < 3)
3824         {
3825             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3826             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3827             // WebGL says that Unsized RGB 16F (OES) can be renderable with
3828             // GL_EXT_color_buffer_half_float.
3829             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3830             TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
3831                                    textureData, readPixelsData);
3832         }
3833 
3834         // Unsized RGB 16F
3835         {
3836             bool texture = false;
3837             bool filter  = false;
3838             bool render  = false;
3839             TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
3840                                    textureData, readPixelsData);
3841         }
3842 
3843         if (getClientMajorVersion() >= 3)
3844         {
3845             // Sized RGB 16F
3846             bool texture = true;
3847             bool filter  = true;
3848             // Renderability of RGB is forbidden by GL_EXT_color_buffer_half_float in WebGL 2.
3849             bool render = false;
3850             TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
3851                                    textureData, readPixelsData);
3852         }
3853         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3854         {
3855             // Sized RGB 16F (OES)
3856             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3857             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3858             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3859             TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
3860                                    textureData, readPixelsData);
3861         }
3862     }
3863 }
3864 
TEST_P(WebGLCompatibilityTest,RGBA16FTextures)3865 TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
3866 {
3867     // http://anglebug.com/42263897
3868     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsMac());
3869 
3870     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
3871 
3872     constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
3873     const GLushort textureData[]     = {
3874         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3875         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3876 
3877     for (auto extension : FloatingPointTextureExtensions)
3878     {
3879         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3880         {
3881             glRequestExtensionANGLE(extension);
3882             ASSERT_GL_NO_ERROR();
3883         }
3884 
3885         // Unsized RGBA 16F (OES)
3886         if (getClientMajorVersion() < 3)
3887         {
3888             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3889             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3890             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3891             TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
3892                                    textureData, readPixelsData);
3893         }
3894 
3895         // Unsized RGBA 16F
3896         {
3897             bool texture = false;
3898             bool filter  = false;
3899             bool render  = false;
3900             TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
3901                                    textureData, readPixelsData);
3902         }
3903 
3904         if (getClientMajorVersion() >= 3)
3905         {
3906             // Sized RGBA 16F
3907             bool texture = true;
3908             bool filter  = true;
3909             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3910                           IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3911             TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
3912                                    textureData, readPixelsData);
3913         }
3914         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3915         {
3916             // Sized RGBA 16F (OES)
3917             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3918             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3919             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3920             TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
3921                                    textureData, readPixelsData);
3922         }
3923     }
3924 }
3925 
3926 // Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
3927 // accepted by glTexImage2D
TEST_P(WebGLCompatibilityTest,SizedRGBA32FFormats)3928 TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
3929 {
3930     // Test skipped because it is only valid for WebGL1 contexts.
3931     ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
3932 
3933     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_OES_texture_float"));
3934 
3935     glRequestExtensionANGLE("GL_OES_texture_float");
3936     ASSERT_GL_NO_ERROR();
3937 
3938     GLTexture texture;
3939     glBindTexture(GL_TEXTURE_2D, texture);
3940 
3941     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3942     // dEQP implicitly defines error code ordering
3943     EXPECT_GL_ERROR(GL_INVALID_ENUM);
3944 
3945     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
3946     // dEQP implicitly defines error code ordering
3947     EXPECT_GL_ERROR(GL_INVALID_ENUM);
3948 
3949     if (IsGLExtensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
3950     {
3951         glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
3952         ASSERT_GL_NO_ERROR();
3953 
3954         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3955         EXPECT_GL_NO_ERROR();
3956     }
3957 
3958     if (IsGLExtensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
3959     {
3960         glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
3961         ASSERT_GL_NO_ERROR();
3962 
3963         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
3964         EXPECT_GL_NO_ERROR();
3965     }
3966 }
3967 
3968 // Verify GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point.
TEST_P(WebGLCompatibilityTest,DepthStencilAttachment)3969 TEST_P(WebGLCompatibilityTest, DepthStencilAttachment)
3970 {
3971     ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
3972 
3973     // Test that attaching a bound texture succeeds.
3974     GLTexture texture;
3975     glBindTexture(GL_TEXTURE_2D, texture);
3976 
3977     GLFramebuffer fbo;
3978     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3979 
3980     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
3981 
3982     GLint attachmentType = 0;
3983     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3984                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
3985     EXPECT_GL_NO_ERROR();
3986     EXPECT_GLENUM_EQ(GL_TEXTURE, attachmentType);
3987 
3988     // Test when if no attach object at the named attachment point and pname is not OBJECT_TYPE.
3989     GLFramebuffer fbo2;
3990     glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
3991 
3992     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3993                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attachmentType);
3994     EXPECT_GL_ERROR(GL_INVALID_ENUM);
3995 }
3996 
3997 // Verify framebuffer attachments return expected types when in an inconsistant state.
TEST_P(WebGLCompatibilityTest,FramebufferAttachmentConsistancy)3998 TEST_P(WebGLCompatibilityTest, FramebufferAttachmentConsistancy)
3999 {
4000     ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
4001 
4002     GLFramebuffer fbo;
4003     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4004 
4005     GLRenderbuffer rb1;
4006     glBindRenderbuffer(GL_RENDERBUFFER, rb1);
4007 
4008     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb1);
4009 
4010     GLint attachmentType = 0;
4011     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
4012                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
4013 
4014     EXPECT_GL_NO_ERROR();
4015     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
4016 
4017     GLRenderbuffer rb2;
4018     glBindRenderbuffer(GL_RENDERBUFFER, rb2);
4019 
4020     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb2);
4021 
4022     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
4023                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
4024 
4025     EXPECT_GL_NO_ERROR();
4026     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
4027 
4028     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb2);
4029 
4030     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
4031                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
4032 
4033     EXPECT_GL_NO_ERROR();
4034     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
4035 
4036     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb2);
4037 
4038     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
4039                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
4040 
4041     EXPECT_GL_NO_ERROR();
4042     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
4043 }
4044 
4045 // This tests that rendering feedback loops works as expected with WebGL 2.
4046 // Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
TEST_P(WebGL2CompatibilityTest,RenderingFeedbackLoopWithDrawBuffers)4047 TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
4048 {
4049     constexpr char kVS[] =
4050         R"(#version 300 es
4051 in vec4 aPosition;
4052 out vec2 texCoord;
4053 void main() {
4054     gl_Position = aPosition;
4055     texCoord = (aPosition.xy * 0.5) + 0.5;
4056 })";
4057 
4058     constexpr char kFS[] =
4059         R"(#version 300 es
4060 precision mediump float;
4061 uniform sampler2D tex;
4062 in vec2 texCoord;
4063 out vec4 oColor;
4064 void main() {
4065     oColor = texture(tex, texCoord);
4066 })";
4067 
4068     GLsizei width  = 8;
4069     GLsizei height = 8;
4070 
4071     GLint maxDrawBuffers = 0;
4072     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
4073     // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
4074     ASSERT_GE(maxDrawBuffers, 2);
4075 
4076     ANGLE_GL_PROGRAM(program, kVS, kFS);
4077     glUseProgram(program);
4078     glViewport(0, 0, width, height);
4079 
4080     GLTexture tex0;
4081     GLTexture tex1;
4082     GLFramebuffer fbo;
4083     FillTexture2D(tex0, width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
4084     FillTexture2D(tex1, width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
4085     ASSERT_GL_NO_ERROR();
4086 
4087     glBindTexture(GL_TEXTURE_2D, tex1);
4088     GLint texLoc = glGetUniformLocation(program, "tex");
4089     ASSERT_NE(-1, texLoc);
4090     glUniform1i(texLoc, 0);
4091 
4092     // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
4093     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4094     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0);
4095     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1, 0);
4096     ASSERT_GL_NO_ERROR();
4097 
4098     drawBuffersFeedbackLoop(program, {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
4099     drawBuffersFeedbackLoop(program, {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
4100                             GL_INVALID_OPERATION);
4101     // A feedback loop is formed regardless of drawBuffers settings.
4102     drawBuffersFeedbackLoop(program, {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_INVALID_OPERATION);
4103 }
4104 
4105 // This tests that texture base level for immutable textures is clamped to the valid range, unlike
4106 // for non-immutable textures, for purposes of validation. Related to WebGL test
4107 // conformance2/textures/misc/immutable-tex-render-feedback.html
TEST_P(WebGL2CompatibilityTest,RenderingFeedbackLoopWithImmutableTextureWithOutOfRangeBaseLevel)4108 TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithImmutableTextureWithOutOfRangeBaseLevel)
4109 {
4110     constexpr char kVS[] =
4111         R"(#version 300 es
4112 in vec4 aPosition;
4113 out vec2 texCoord;
4114 void main() {
4115     gl_Position = aPosition;
4116     texCoord = (aPosition.xy * 0.5) + 0.5;
4117 })";
4118 
4119     constexpr char kFS[] =
4120         R"(#version 300 es
4121 precision mediump float;
4122 uniform sampler2D tex;
4123 in vec2 texCoord;
4124 out vec4 oColor;
4125 void main() {
4126     oColor = texture(tex, texCoord);
4127 })";
4128 
4129     GLTexture texture;
4130     glBindTexture(GL_TEXTURE_2D, texture);
4131     glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4);
4132     std::vector<GLColor> texData(4 * 4, GLColor::green);
4133     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, texData.data());
4134     // Set a base level greater than the max level. It should be clamped to the actual max level.
4135     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
4136     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
4137 
4138     ASSERT_GL_NO_ERROR();
4139 
4140     GLFramebuffer framebuffer;
4141     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
4142     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
4143 
4144     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
4145 
4146     ANGLE_GL_PROGRAM(program, kVS, kFS);
4147 
4148     GLint uniformLoc = glGetUniformLocation(program, "tex");
4149     ASSERT_NE(-1, uniformLoc);
4150 
4151     glUseProgram(program);
4152     glUniform1i(uniformLoc, 0);
4153     glDisable(GL_BLEND);
4154     glDisable(GL_DEPTH_TEST);
4155     ASSERT_GL_NO_ERROR();
4156 
4157     // Ensure that the texture can be used for rendering.
4158     glBindFramebuffer(GL_FRAMEBUFFER, 0);
4159     glBindTexture(GL_TEXTURE_2D, texture);
4160     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4161     ASSERT_GL_NO_ERROR();
4162     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4163 
4164     // Ensure that the texture can't be used to create a feedback loop.
4165     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
4166     glBindTexture(GL_TEXTURE_2D, texture);
4167     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4168     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4169 }
4170 
4171 // This test covers detection of rendering feedback loops between the FBO and a depth Texture.
4172 // Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
TEST_P(WebGL2CompatibilityTest,RenderingFeedbackLoopWithDepthStencil)4173 TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
4174 {
4175     constexpr char kVS[] =
4176         R"(#version 300 es
4177 in vec4 aPosition;
4178 out vec2 texCoord;
4179 void main() {
4180     gl_Position = aPosition;
4181     texCoord = (aPosition.xy * 0.5) + 0.5;
4182 })";
4183 
4184     constexpr char kFS[] =
4185         R"(#version 300 es
4186 precision mediump float;
4187 uniform sampler2D tex;
4188 in vec2 texCoord;
4189 out vec4 oColor;
4190 void main() {
4191     oColor = texture(tex, texCoord);
4192 })";
4193 
4194     GLsizei width  = 8;
4195     GLsizei height = 8;
4196 
4197     ANGLE_GL_PROGRAM(program, kVS, kFS);
4198     glUseProgram(program);
4199 
4200     glViewport(0, 0, width, height);
4201 
4202     GLint texLoc = glGetUniformLocation(program, "tex");
4203     glUniform1i(texLoc, 0);
4204 
4205     // Create textures and allocate storage
4206     GLTexture tex0;
4207     GLTexture tex1;
4208     GLTexture tex2;
4209     FillTexture2D(tex0, width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
4210     FillTexture2D(tex1, width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
4211                   GL_UNSIGNED_INT);
4212     FillTexture2D(tex2, width, height, 0x40, 0, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
4213                   GL_UNSIGNED_INT_24_8);
4214     ASSERT_GL_NO_ERROR();
4215 
4216     GLFramebuffer fbo;
4217     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4218     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0);
4219 
4220     // Test rendering and sampling feedback loop for depth buffer
4221     glBindTexture(GL_TEXTURE_2D, tex1);
4222     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1, 0);
4223     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
4224 
4225     // The same image is used as depth buffer during rendering.
4226     glEnable(GL_DEPTH_TEST);
4227     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4228     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Same image as depth buffer should fail";
4229 
4230     // The same image is used as depth buffer. But depth mask is false.
4231     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4232     glDepthMask(GL_FALSE);
4233     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4234     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Depth writes disabled should still fail";
4235 
4236     // The same image is used as depth buffer. But depth test is not enabled during rendering.
4237     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4238     glDepthMask(GL_TRUE);
4239     glDisable(GL_DEPTH_TEST);
4240     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4241     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Depth read disabled should still fail";
4242 
4243     // Test rendering and sampling feedback loop for stencil buffer
4244     glBindTexture(GL_TEXTURE_2D, tex2);
4245     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
4246     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, tex2, 0);
4247     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
4248     constexpr GLint stencilClearValue = 0x40;
4249     glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
4250 
4251     // The same image is used as stencil buffer during rendering.
4252     glEnable(GL_STENCIL_TEST);
4253     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4254     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Same image as stencil buffer should fail";
4255 
4256     // The same image is used as stencil buffer. But stencil mask is zero.
4257     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4258     glStencilMask(0x0);
4259     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4260     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Stencil mask zero should still fail";
4261 
4262     // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
4263     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4264     glStencilMask(0xffff);
4265     glDisable(GL_STENCIL_TEST);
4266     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
4267     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Stencil test disabled should still fail";
4268 }
4269 
4270 // The source and the target for CopyTexSubImage3D are the same 3D texture.
4271 // But the level of the 3D texture != the level of the read attachment.
TEST_P(WebGL2CompatibilityTest,NoTextureCopyingFeedbackLoopBetween3DLevels)4272 TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
4273 {
4274     GLTexture texture;
4275     GLFramebuffer framebuffer;
4276 
4277     glBindTexture(GL_TEXTURE_3D, texture);
4278     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
4279 
4280     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4281     glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4282     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
4283     ASSERT_GL_NO_ERROR();
4284 
4285     glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
4286     EXPECT_GL_NO_ERROR();
4287 }
4288 
4289 // The source and the target for CopyTexSubImage3D are the same 3D texture.
4290 // But the zoffset of the 3D texture != the layer of the read attachment.
TEST_P(WebGL2CompatibilityTest,NoTextureCopyingFeedbackLoopBetween3DLayers)4291 TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
4292 {
4293     GLTexture texture;
4294     GLFramebuffer framebuffer;
4295 
4296     glBindTexture(GL_TEXTURE_3D, texture);
4297     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
4298 
4299     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4300     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 1);
4301     ASSERT_GL_NO_ERROR();
4302 
4303     glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
4304     EXPECT_GL_NO_ERROR();
4305 }
4306 
4307 // The source and the target for CopyTexSubImage3D are the same 3D texture.
4308 // And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
TEST_P(WebGL2CompatibilityTest,TextureCopyingFeedbackLoop3D)4309 TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
4310 {
4311     GLTexture texture;
4312     GLFramebuffer framebuffer;
4313 
4314     glBindTexture(GL_TEXTURE_3D, texture);
4315     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
4316 
4317     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4318     glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4319     glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4320     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 1, 0);
4321     ASSERT_GL_NO_ERROR();
4322 
4323     glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
4324     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4325 }
4326 
4327 // Verify that errors are generated when there isn't a defined conversion between the clear type and
4328 // the buffer type.
TEST_P(WebGL2CompatibilityTest,ClearBufferTypeCompatibity)4329 TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
4330 {
4331     // Test skipped for D3D11 because it generates D3D11 runtime warnings.
4332     ANGLE_SKIP_TEST_IF(IsD3D11());
4333 
4334     constexpr float clearFloat[]       = {0.0f, 0.0f, 0.0f, 0.0f};
4335     constexpr int clearInt[]           = {0, 0, 0, 0};
4336     constexpr unsigned int clearUint[] = {0, 0, 0, 0};
4337 
4338     GLTexture texture;
4339     GLFramebuffer framebuffer;
4340 
4341     glBindTexture(GL_TEXTURE_2D, texture);
4342     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
4343 
4344     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
4345     ASSERT_GL_NO_ERROR();
4346 
4347     // Unsigned integer buffer
4348     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
4349     ASSERT_GL_NO_ERROR();
4350 
4351     glClearBufferfv(GL_COLOR, 0, clearFloat);
4352     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4353 
4354     glClearBufferiv(GL_COLOR, 0, clearInt);
4355     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4356 
4357     glClearBufferuiv(GL_COLOR, 0, clearUint);
4358     EXPECT_GL_NO_ERROR();
4359 
4360     glClear(GL_COLOR_BUFFER_BIT);
4361     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4362 
4363     // Integer buffer
4364     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
4365     ASSERT_GL_NO_ERROR();
4366 
4367     glClearBufferfv(GL_COLOR, 0, clearFloat);
4368     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4369 
4370     glClearBufferiv(GL_COLOR, 0, clearInt);
4371     EXPECT_GL_NO_ERROR();
4372 
4373     glClearBufferuiv(GL_COLOR, 0, clearUint);
4374     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4375 
4376     glClear(GL_COLOR_BUFFER_BIT);
4377     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4378 
4379     // Float buffer
4380     if (IsGLExtensionRequestable("GL_EXT_color_buffer_float"))
4381     {
4382         glRequestExtensionANGLE("GL_EXT_color_buffer_float");
4383     }
4384 
4385     if (IsGLExtensionEnabled("GL_EXT_color_buffer_float"))
4386     {
4387         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
4388         ASSERT_GL_NO_ERROR();
4389 
4390         glClearBufferfv(GL_COLOR, 0, clearFloat);
4391         EXPECT_GL_NO_ERROR();
4392 
4393         glClearBufferiv(GL_COLOR, 0, clearInt);
4394         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4395 
4396         glClearBufferuiv(GL_COLOR, 0, clearUint);
4397         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4398 
4399         glClear(GL_COLOR_BUFFER_BIT);
4400         EXPECT_GL_NO_ERROR();
4401     }
4402 
4403     // Normalized uint buffer
4404     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4405     ASSERT_GL_NO_ERROR();
4406 
4407     glClearBufferfv(GL_COLOR, 0, clearFloat);
4408     EXPECT_GL_NO_ERROR();
4409 
4410     glClearBufferiv(GL_COLOR, 0, clearInt);
4411     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4412 
4413     glClearBufferuiv(GL_COLOR, 0, clearUint);
4414     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4415 
4416     glClear(GL_COLOR_BUFFER_BIT);
4417     EXPECT_GL_NO_ERROR();
4418 }
4419 
4420 // Test the interaction of WebGL compatibility clears with default framebuffers
TEST_P(WebGL2CompatibilityTest,ClearBufferDefaultFramebuffer)4421 TEST_P(WebGL2CompatibilityTest, ClearBufferDefaultFramebuffer)
4422 {
4423     constexpr float clearFloat[]       = {0.0f, 0.0f, 0.0f, 0.0f};
4424     constexpr int clearInt[]           = {0, 0, 0, 0};
4425     constexpr unsigned int clearUint[] = {0, 0, 0, 0};
4426 
4427     // glClear works as usual, this is also a regression test for a bug where we
4428     // iterated on maxDrawBuffers for default framebuffers, triggering an assert
4429     glClear(GL_COLOR_BUFFER_BIT);
4430     EXPECT_GL_NO_ERROR();
4431 
4432     // Default framebuffers are normalized uints, so only glClearBufferfv works.
4433     glClearBufferfv(GL_COLOR, 0, clearFloat);
4434     EXPECT_GL_NO_ERROR();
4435 
4436     glClearBufferiv(GL_COLOR, 0, clearInt);
4437     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4438 
4439     glClearBufferuiv(GL_COLOR, 0, clearUint);
4440     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4441 }
4442 
4443 // Test that clearing a non-existent drawbuffer of the default
4444 // framebuffer does not cause an assertion in WebGL validation
TEST_P(WebGL2CompatibilityTest,ClearBuffer1OnDefaultFramebufferNoAssert)4445 TEST_P(WebGL2CompatibilityTest, ClearBuffer1OnDefaultFramebufferNoAssert)
4446 {
4447     constexpr float clearFloat[]   = {0.0f, 0.0f, 0.0f, 0.0f};
4448     constexpr int32_t clearInt[]   = {0, 0, 0, 0};
4449     constexpr uint32_t clearUint[] = {0, 0, 0, 0};
4450 
4451     glClearBufferfv(GL_COLOR, 1, clearFloat);
4452     EXPECT_GL_NO_ERROR();
4453 
4454     glClearBufferiv(GL_COLOR, 1, clearInt);
4455     EXPECT_GL_NO_ERROR();
4456 
4457     glClearBufferuiv(GL_COLOR, 1, clearUint);
4458     EXPECT_GL_NO_ERROR();
4459 }
4460 
4461 // Verify that errors are generate when trying to blit from an image to itself
TEST_P(WebGL2CompatibilityTest,BlitFramebufferSameImage)4462 TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
4463 {
4464     GLTexture textures[2];
4465     glBindTexture(GL_TEXTURE_2D, textures[0]);
4466     glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
4467     glBindTexture(GL_TEXTURE_2D, textures[1]);
4468     glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
4469 
4470     GLRenderbuffer renderbuffers[2];
4471     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
4472     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
4473     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
4474     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
4475 
4476     GLFramebuffer framebuffers[2];
4477     glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
4478     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
4479 
4480     ASSERT_GL_NO_ERROR();
4481 
4482     // Same texture
4483     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
4484                            0);
4485     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
4486                            0);
4487     ASSERT_GL_NO_ERROR();
4488     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4489     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4490 
4491     // Same textures but different renderbuffers
4492     glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4493                               renderbuffers[0]);
4494     glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4495                               renderbuffers[1]);
4496     ASSERT_GL_NO_ERROR();
4497     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
4498     ASSERT_GL_NO_ERROR();
4499     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4500                       GL_NEAREST);
4501     ASSERT_GL_NO_ERROR();
4502     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
4503                       GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4504                       GL_NEAREST);
4505     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4506 
4507     // Same renderbuffers but different textures
4508     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
4509                            0);
4510     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
4511                            0);
4512     glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4513                               renderbuffers[0]);
4514     glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4515                               renderbuffers[0]);
4516     ASSERT_GL_NO_ERROR();
4517     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4518     ASSERT_GL_NO_ERROR();
4519     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4520                       GL_NEAREST);
4521     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4522     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
4523                       GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4524                       GL_NEAREST);
4525     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4526 }
4527 
4528 // Verify that errors are generated when the fragment shader output doesn't match the bound color
4529 // buffer types
TEST_P(WebGL2CompatibilityTest,FragmentShaderColorBufferTypeMissmatch)4530 TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
4531 {
4532     constexpr char kVS[] =
4533         R"(#version 300 es
4534 void main() {
4535     gl_Position = vec4(0, 0, 0, 1);
4536 })";
4537 
4538     constexpr char kFS[] =
4539         R"(#version 300 es
4540 precision mediump float;
4541 layout(location = 0) out vec4 floatOutput;
4542 layout(location = 1) out uvec4 uintOutput;
4543 layout(location = 2) out ivec4 intOutput;
4544 void main() {
4545     floatOutput = vec4(0, 0, 0, 1);
4546     uintOutput = uvec4(0, 0, 0, 1);
4547     intOutput = ivec4(0, 0, 0, 1);
4548 })";
4549 
4550     ANGLE_GL_PROGRAM(program, kVS, kFS);
4551     glUseProgram(program);
4552 
4553     GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
4554     GLuint uintLocation  = glGetFragDataLocation(program, "uintOutput");
4555     GLuint intLocation   = glGetFragDataLocation(program, "intOutput");
4556 
4557     GLFramebuffer fbo;
4558     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4559 
4560     GLRenderbuffer floatRenderbuffer;
4561     glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
4562     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
4563     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
4564                               floatRenderbuffer);
4565 
4566     GLRenderbuffer uintRenderbuffer;
4567     glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
4568     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
4569     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4570                               uintRenderbuffer);
4571 
4572     GLRenderbuffer intRenderbuffer;
4573     glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
4574     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
4575     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4576                               intRenderbuffer);
4577 
4578     ASSERT_GL_NO_ERROR();
4579 
4580     GLint maxDrawBuffers = 0;
4581     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
4582     std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
4583     drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
4584     drawBuffers[uintLocation]  = GL_COLOR_ATTACHMENT0 + uintLocation;
4585     drawBuffers[intLocation]   = GL_COLOR_ATTACHMENT0 + intLocation;
4586 
4587     glDrawBuffers(maxDrawBuffers, drawBuffers.data());
4588 
4589     // Check that the correct case generates no errors
4590     glDrawArrays(GL_TRIANGLES, 0, 6);
4591     EXPECT_GL_NO_ERROR();
4592 
4593     // Unbind some buffers and verify that there are still no errors
4594     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4595                               0);
4596     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4597                               0);
4598     glDrawArrays(GL_TRIANGLES, 0, 6);
4599     EXPECT_GL_NO_ERROR();
4600 
4601     // Swap the int and uint buffers to and verify that an error is generated
4602     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4603                               intRenderbuffer);
4604     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4605                               uintRenderbuffer);
4606     glDrawArrays(GL_TRIANGLES, 0, 6);
4607     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4608 
4609     // Swap the float and uint buffers to and verify that an error is generated
4610     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4611                               floatRenderbuffer);
4612     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
4613                               uintRenderbuffer);
4614     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4615                               intRenderbuffer);
4616     glDrawArrays(GL_TRIANGLES, 0, 6);
4617     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4618 }
4619 
4620 // Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
4621 // types
TEST_P(WebGL2CompatibilityTest,VertexShaderAttributeTypeMismatch)4622 TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMismatch)
4623 {
4624     constexpr char kVS[] =
4625         R"(#version 300 es
4626 in vec4 floatInput;
4627 in uvec4 uintInput;
4628 in ivec4 intInput;
4629 void main() {
4630     gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);
4631 })";
4632 
4633     constexpr char kFS[] =
4634         R"(#version 300 es
4635 precision mediump float;
4636 out vec4 outputColor;
4637 void main() {
4638     outputColor = vec4(0, 0, 0, 1);
4639 })";
4640 
4641     ANGLE_GL_PROGRAM(program, kVS, kFS);
4642     glUseProgram(program);
4643 
4644     GLint floatLocation = glGetAttribLocation(program, "floatInput");
4645     GLint uintLocation  = glGetAttribLocation(program, "uintInput");
4646     GLint intLocation   = glGetAttribLocation(program, "intInput");
4647 
4648     // Default attributes are of float types
4649     glDrawArrays(GL_TRIANGLES, 0, 6);
4650     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4651 
4652     // Set the default attributes to the correct types, should succeed
4653     glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
4654     glVertexAttribI4i(intLocation, 0, 0, 0, 1);
4655     glDrawArrays(GL_TRIANGLES, 0, 6);
4656     EXPECT_GL_NO_ERROR();
4657 
4658     // Change the default float attribute to an integer, should fail
4659     glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
4660     glDrawArrays(GL_TRIANGLES, 0, 6);
4661     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4662 
4663     // Use a buffer for some attributes
4664     GLBuffer buffer;
4665     glBindBuffer(GL_ARRAY_BUFFER, buffer);
4666     glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
4667     glEnableVertexAttribArray(floatLocation);
4668     glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
4669     glDrawArrays(GL_TRIANGLES, 0, 6);
4670     EXPECT_GL_NO_ERROR();
4671 
4672     // Use a float pointer attrib for a uint input
4673     glEnableVertexAttribArray(uintLocation);
4674     glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
4675     glDrawArrays(GL_TRIANGLES, 0, 6);
4676     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4677 
4678     // Use a uint pointer for the uint input
4679     glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
4680     glDrawArrays(GL_TRIANGLES, 0, 6);
4681     EXPECT_GL_NO_ERROR();
4682 }
4683 
4684 // Test that it's not possible to query the non-zero color attachments without the drawbuffers
4685 // extension in WebGL1
TEST_P(WebGLCompatibilityTest,FramebufferAttachmentQuery)4686 TEST_P(WebGLCompatibilityTest, FramebufferAttachmentQuery)
4687 {
4688     ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
4689     ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_EXT_draw_buffers"));
4690 
4691     GLFramebuffer fbo;
4692     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4693     EXPECT_GL_NO_ERROR();
4694 
4695     GLint result;
4696     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
4697                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &result);
4698     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4699 
4700     GLRenderbuffer renderbuffer;
4701     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
4702     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
4703     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, renderbuffer);
4704     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4705 }
4706 
4707 // Tests WebGL reports INVALID_OPERATION for mismatch of drawbuffers and fragment output
TEST_P(WebGLCompatibilityTest,DrawBuffers)4708 TEST_P(WebGLCompatibilityTest, DrawBuffers)
4709 {
4710     // Make sure we can use at least 4 attachments for the tests.
4711     bool useEXT = false;
4712     if (getClientMajorVersion() < 3)
4713     {
4714         ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_EXT_draw_buffers"));
4715 
4716         glRequestExtensionANGLE("GL_EXT_draw_buffers");
4717         useEXT = true;
4718         EXPECT_GL_NO_ERROR();
4719     }
4720 
4721     GLint maxDrawBuffers = 0;
4722     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
4723     // Test skipped because MAX_DRAW_BUFFERS is too small.
4724     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
4725 
4726     // Clears all the renderbuffers to red.
4727     auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
4728         GLFramebuffer clearFBO;
4729         glBindFramebuffer(GL_FRAMEBUFFER, clearFBO);
4730 
4731         glClearColor(1, 0, 0, 1);
4732         for (int i = 0; i < 4; ++i)
4733         {
4734             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
4735                                       renderbuffers[i]);
4736             glClear(GL_COLOR_BUFFER_BIT);
4737         }
4738         ASSERT_GL_NO_ERROR();
4739     };
4740 
4741     // Checks that the renderbuffers specified by mask have the correct color
4742     auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
4743         GLFramebuffer readFBO;
4744         glBindFramebuffer(GL_FRAMEBUFFER, readFBO);
4745 
4746         for (int attachmentIndex = 0; attachmentIndex < 4; ++attachmentIndex)
4747         {
4748             if (mask & (1 << attachmentIndex))
4749             {
4750                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
4751                                           renderbuffers[attachmentIndex]);
4752                 EXPECT_PIXEL_COLOR_EQ(0, 0, color) << "attachment " << attachmentIndex;
4753             }
4754         }
4755         ASSERT_GL_NO_ERROR();
4756     };
4757 
4758     // Depending on whether we are using the extension or ES3, a different entrypoint must be called
4759     auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
4760         if (useEXT)
4761         {
4762             glDrawBuffersEXT(numBuffers, buffers);
4763         }
4764         else
4765         {
4766             glDrawBuffers(numBuffers, buffers);
4767         }
4768     };
4769 
4770     // Initialized the test framebuffer
4771     GLFramebuffer drawFBO;
4772     glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4773 
4774     GLRenderbuffer renderbuffers[4];
4775     for (int i = 0; i < 4; ++i)
4776     {
4777         glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
4778         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
4779         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
4780                                   renderbuffers[i]);
4781     }
4782 
4783     ASSERT_GL_NO_ERROR();
4784 
4785     GLenum allDrawBuffers[] = {
4786         GL_COLOR_ATTACHMENT0,
4787         GL_COLOR_ATTACHMENT1,
4788         GL_COLOR_ATTACHMENT2,
4789         GL_COLOR_ATTACHMENT3,
4790     };
4791 
4792     GLenum halfDrawBuffers[] = {
4793         GL_NONE,
4794         GL_COLOR_ATTACHMENT1,
4795         GL_NONE,
4796         GL_COLOR_ATTACHMENT3,
4797     };
4798 
4799     // Test that when using gl_FragColor with no-array
4800     const char *fragESSL1 =
4801         R"(precision highp float;
4802 void main()
4803 {
4804     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
4805 })";
4806     ANGLE_GL_PROGRAM(programESSL1, essl1_shaders::vs::Simple(), fragESSL1);
4807 
4808     {
4809         glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4810         DrawBuffers(useEXT, 4, allDrawBuffers);
4811         drawQuad(programESSL1, essl1_shaders::PositionAttrib(), 0.5, 1.0, true);
4812         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4813     }
4814 
4815     // Test what happens when rendering to a subset of the outputs. There is a behavior difference
4816     // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
4817     // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
4818     // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
4819     // attachments not declared in the shader should not be written to.
4820     const char *positionAttrib;
4821     const char *writeOddOutputsVert;
4822     const char *writeOddOutputsFrag;
4823     if (useEXT)
4824     {
4825         positionAttrib      = essl1_shaders::PositionAttrib();
4826         writeOddOutputsVert = essl1_shaders::vs::Simple();
4827         writeOddOutputsFrag =
4828             R"(#extension GL_EXT_draw_buffers : require
4829 precision highp float;
4830 void main()
4831 {
4832     gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);
4833     gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);
4834 })";
4835     }
4836     else
4837     {
4838         positionAttrib      = essl3_shaders::PositionAttrib();
4839         writeOddOutputsVert = essl3_shaders::vs::Simple();
4840         writeOddOutputsFrag =
4841             R"(#version 300 es
4842 precision highp float;
4843 layout(location = 1) out vec4 output1;
4844 layout(location = 3) out vec4 output2;
4845 void main()
4846 {
4847     output1 = vec4(0.0, 1.0, 0.0, 1.0);
4848     output2 = vec4(0.0, 1.0, 0.0, 1.0);
4849 })";
4850     }
4851     ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
4852 
4853     // Test that attachments not written to get the "unwritten" color (useEXT)
4854     // Or INVALID_OPERATION is generated if there's active draw buffer receive no output
4855     {
4856         ClearEverythingToRed(renderbuffers);
4857 
4858         glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4859         DrawBuffers(useEXT, 4, allDrawBuffers);
4860         drawQuad(writeOddOutputsProgram, positionAttrib, 0.5, 1.0, true);
4861 
4862         if (useEXT)
4863         {
4864             ASSERT_GL_NO_ERROR();
4865             CheckColors(renderbuffers, 0b1010, GLColor::green);
4866             // In the extension, when an attachment isn't written to, it should get 0's
4867             CheckColors(renderbuffers, 0b0101, GLColor(0, 0, 0, 0));
4868         }
4869         else
4870         {
4871             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4872         }
4873     }
4874 
4875     // Test that attachments written to get the correct color from shader output but that even when
4876     // the extension is used, disabled attachments are not written at all and stay red.
4877     {
4878         ClearEverythingToRed(renderbuffers);
4879 
4880         glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4881         DrawBuffers(useEXT, 4, halfDrawBuffers);
4882         drawQuad(writeOddOutputsProgram, positionAttrib, 0.5, 1.0, true);
4883         ASSERT_GL_NO_ERROR();
4884 
4885         CheckColors(renderbuffers, 0b1010, GLColor::green);
4886         CheckColors(renderbuffers, 0b0101, GLColor::red);
4887     }
4888 }
4889 
4890 // Test that it's possible to generate mipmaps on unsized floating point textures once the
4891 // extensions have been enabled
TEST_P(WebGLCompatibilityTest,GenerateMipmapUnsizedFloatingPointTexture)4892 TEST_P(WebGLCompatibilityTest, GenerateMipmapUnsizedFloatingPointTexture)
4893 {
4894     glRequestExtensionANGLE("GL_OES_texture_float");
4895     glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
4896     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
4897     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
4898 
4899     GLTexture texture;
4900     glBindTexture(GL_TEXTURE_2D, texture);
4901 
4902     constexpr GLColor32F data[4] = {
4903         kFloatRed,
4904         kFloatRed,
4905         kFloatGreen,
4906         kFloatBlue,
4907     };
4908     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_FLOAT, data);
4909     ASSERT_GL_NO_ERROR();
4910 
4911     glGenerateMipmap(GL_TEXTURE_2D);
4912     EXPECT_GL_NO_ERROR();
4913 }
4914 // Test that it's possible to generate mipmaps on unsized floating point textures once the
4915 // extensions have been enabled
TEST_P(WebGLCompatibilityTest,GenerateMipmapSizedFloatingPointTexture)4916 TEST_P(WebGLCompatibilityTest, GenerateMipmapSizedFloatingPointTexture)
4917 {
4918     if (IsGLExtensionRequestable("GL_OES_texture_float"))
4919     {
4920         glRequestExtensionANGLE("GL_OES_texture_float");
4921     }
4922     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
4923 
4924     if (IsGLExtensionRequestable("GL_EXT_texture_storage"))
4925     {
4926         glRequestExtensionANGLE("GL_EXT_texture_storage");
4927     }
4928     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
4929 
4930     GLTexture texture;
4931     glBindTexture(GL_TEXTURE_2D, texture);
4932 
4933     constexpr GLColor32F data[4] = {
4934         kFloatRed,
4935         kFloatRed,
4936         kFloatGreen,
4937         kFloatBlue,
4938     };
4939     glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA32F, 2, 2);
4940     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_FLOAT, data);
4941     ASSERT_GL_NO_ERROR();
4942 
4943     glGenerateMipmap(GL_TEXTURE_2D);
4944     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4945 
4946     if (IsGLExtensionRequestable("GL_EXT_color_buffer_float"))
4947     {
4948         // Format is renderable but not filterable
4949         glRequestExtensionANGLE("GL_EXT_color_buffer_float");
4950         glGenerateMipmap(GL_TEXTURE_2D);
4951         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4952     }
4953 
4954     if (IsGLExtensionRequestable("GL_EXT_color_buffer_float_linear"))
4955     {
4956         // Format is renderable but not filterable
4957         glRequestExtensionANGLE("GL_EXT_color_buffer_float_linear");
4958 
4959         if (IsGLExtensionEnabled("GL_EXT_color_buffer_float"))
4960         {
4961             // Format is filterable and renderable
4962             glGenerateMipmap(GL_TEXTURE_2D);
4963             EXPECT_GL_NO_ERROR();
4964         }
4965         else
4966         {
4967             // Format is filterable but not renderable
4968             glGenerateMipmap(GL_TEXTURE_2D);
4969             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4970         }
4971     }
4972 }
4973 
4974 // Verify that a texture format is only allowed with extension enabled.
validateTexImageExtensionFormat(GLenum format,const std::string & extName)4975 void WebGLCompatibilityTest::validateTexImageExtensionFormat(GLenum format,
4976                                                              const std::string &extName)
4977 {
4978     // Verify texture format fails by default.
4979     glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, GL_UNSIGNED_BYTE, nullptr);
4980     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4981 
4982     if (IsGLExtensionRequestable(extName))
4983     {
4984         // Verify texture format is allowed once extension is enabled.
4985         glRequestExtensionANGLE(extName.c_str());
4986         EXPECT_TRUE(IsGLExtensionEnabled(extName));
4987 
4988         glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, GL_UNSIGNED_BYTE, nullptr);
4989         ASSERT_GL_NO_ERROR();
4990     }
4991 }
4992 
4993 // Test enabling various non-compressed texture format extensions
TEST_P(WebGLCompatibilityTest,EnableTextureFormatExtensions)4994 TEST_P(WebGLCompatibilityTest, EnableTextureFormatExtensions)
4995 {
4996     ANGLE_SKIP_TEST_IF(IsOzone());
4997     ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
4998 
4999     GLTexture texture;
5000     glBindTexture(GL_TEXTURE_2D, texture);
5001 
5002     // Verify valid format is allowed.
5003     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
5004     ASSERT_GL_NO_ERROR();
5005 
5006     // Verify invalid format fails.
5007     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA32F, GL_UNSIGNED_BYTE, nullptr);
5008     EXPECT_GL_ERROR(GL_INVALID_ENUM);
5009 
5010     // Verify formats from enableable extensions.
5011     if (!IsOpenGLES())
5012     {
5013         validateTexImageExtensionFormat(GL_RED_EXT, "GL_EXT_texture_rg");
5014     }
5015 
5016     validateTexImageExtensionFormat(GL_SRGB_EXT, "GL_EXT_texture_sRGB");
5017     validateTexImageExtensionFormat(GL_BGRA_EXT, "GL_EXT_texture_format_BGRA8888");
5018 }
5019 
validateCompressedTexImageExtensionFormat(GLenum format,GLsizei width,GLsizei height,GLsizei blockSize,const std::string & extName,bool subImageAllowed)5020 void WebGLCompatibilityTest::validateCompressedTexImageExtensionFormat(GLenum format,
5021                                                                        GLsizei width,
5022                                                                        GLsizei height,
5023                                                                        GLsizei blockSize,
5024                                                                        const std::string &extName,
5025                                                                        bool subImageAllowed)
5026 {
5027     std::vector<GLubyte> data(blockSize, 0u);
5028 
5029     GLTexture texture;
5030     glBindTexture(GL_TEXTURE_2D, texture);
5031 
5032     // Verify texture format fails by default.
5033     glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, blockSize, data.data());
5034     EXPECT_GL_ERROR(GL_INVALID_ENUM);
5035 
5036     if (IsGLExtensionRequestable(extName))
5037     {
5038         // Verify texture format is allowed once extension is enabled.
5039         glRequestExtensionANGLE(extName.c_str());
5040         EXPECT_TRUE(IsGLExtensionEnabled(extName));
5041 
5042         glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, blockSize, data.data());
5043         EXPECT_GL_NO_ERROR();
5044 
5045         glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, blockSize,
5046                                   data.data());
5047         if (subImageAllowed)
5048         {
5049             EXPECT_GL_NO_ERROR();
5050         }
5051         else
5052         {
5053             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5054         }
5055     }
5056 }
5057 
expectedByteLength(GLenum format,GLsizei width,GLsizei height)5058 GLint WebGLCompatibilityTest::expectedByteLength(GLenum format, GLsizei width, GLsizei height)
5059 {
5060     switch (format)
5061     {
5062         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5063         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
5064         case GL_COMPRESSED_RED_RGTC1_EXT:
5065         case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
5066             return ((width + 3) / 4) * ((height + 3) / 4) * 8;
5067         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
5068         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5069         case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
5070         case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
5071         case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
5072         case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:
5073         case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
5074         case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
5075             return ((width + 3) / 4) * ((height + 3) / 4) * 16;
5076     }
5077 
5078     UNREACHABLE();
5079     return 0;
5080 }
5081 
testCompressedTexLevelDimension(GLenum format,GLint level,GLsizei width,GLsizei height,GLsizei expectedByteLength,GLenum expectedError,const char * explanation)5082 void WebGLCompatibilityTest::testCompressedTexLevelDimension(GLenum format,
5083                                                              GLint level,
5084                                                              GLsizei width,
5085                                                              GLsizei height,
5086                                                              GLsizei expectedByteLength,
5087                                                              GLenum expectedError,
5088                                                              const char *explanation)
5089 {
5090     std::vector<uint8_t> tempVector(expectedByteLength, 0);
5091 
5092     EXPECT_GL_NO_ERROR();
5093 
5094     GLTexture sourceTexture;
5095     glBindTexture(GL_TEXTURE_2D, sourceTexture);
5096     glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, expectedByteLength,
5097                            tempVector.data());
5098     if (expectedError == 0)
5099     {
5100         EXPECT_GL_NO_ERROR() << explanation;
5101     }
5102     else
5103     {
5104         EXPECT_GL_ERROR(expectedError) << explanation;
5105     }
5106 
5107     if (level == 0 && width > 0)
5108     {
5109         GLTexture sourceTextureStorage;
5110         glBindTexture(GL_TEXTURE_2D, sourceTextureStorage);
5111 
5112         if (getClientMajorVersion() >= 3)
5113         {
5114             glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height);
5115             if (expectedError == 0)
5116             {
5117                 EXPECT_GL_NO_ERROR() << explanation << " (texStorage2D)";
5118             }
5119             else
5120             {
5121                 EXPECT_GL_ERROR(expectedError) << explanation << " (texStorage2D)";
5122             }
5123         }
5124         else
5125         {
5126             if (IsGLExtensionRequestable("GL_EXT_texture_storage"))
5127             {
5128                 glRequestExtensionANGLE("GL_EXT_texture_storage");
5129                 ASSERT_TRUE(IsGLExtensionEnabled("GL_EXT_texture_storage"));
5130 
5131                 glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, width, height);
5132                 if (expectedError == 0)
5133                 {
5134                     EXPECT_GL_NO_ERROR() << explanation << " (texStorage2DEXT)";
5135                 }
5136                 else
5137                 {
5138                     EXPECT_GL_ERROR(expectedError) << explanation << " (texStorage2DEXT)";
5139                 }
5140             }
5141         }
5142     }
5143 }
5144 
testCompressedTexImage(GLenum format)5145 void WebGLCompatibilityTest::testCompressedTexImage(GLenum format)
5146 {
5147     struct TestCase
5148     {
5149         GLint level;
5150         GLsizei width;
5151         GLsizei height;
5152         GLenum expectedError;
5153         const char *explanation;
5154     };
5155 
5156     constexpr TestCase testCases[] = {
5157         {0, 4, 3, GL_INVALID_OPERATION, "level is 0, height is not a multiple of 4"},
5158         {0, 3, 4, GL_INVALID_OPERATION, "level is 0, width is not a multiple of 4"},
5159         {0, 2, 2, GL_INVALID_OPERATION, "level is 0, width is not a multiple of 4"},
5160         {0, 4, 4, GL_NO_ERROR, "is valid"},
5161         {1, 1, 1, GL_INVALID_OPERATION, "implied base mip 2x2 is invalid"},
5162         {1, 1, 2, GL_INVALID_OPERATION, "implied base mip 2x4 is invalid"},
5163         {1, 2, 1, GL_INVALID_OPERATION, "implied base mip 4x2 is invalid"},
5164         {1, 2, 2, GL_NO_ERROR, "implied base mip 4x4 is valid"},
5165     };
5166 
5167     constexpr TestCase webgl2TestCases[] = {
5168         {0, 0, 0, GL_NO_ERROR, "0: 0x0 is valid"},
5169         {0, 1, 1, GL_INVALID_OPERATION, "0: 1x1 is invalid"},
5170         {0, 2, 2, GL_INVALID_OPERATION, "0: 2x2 is invalid"},
5171         {0, 3, 3, GL_INVALID_OPERATION, "0: 3x3 is invalid"},
5172         {0, 10, 10, GL_INVALID_OPERATION, "0: 10x10 is invalid"},
5173         {0, 11, 11, GL_INVALID_OPERATION, "0: 11x11 is invalid"},
5174         {0, 11, 12, GL_INVALID_OPERATION, "0: 11x12 is invalid"},
5175         {0, 12, 11, GL_INVALID_OPERATION, "0: 12x11 is invalid"},
5176         {0, 12, 12, GL_NO_ERROR, "0: 12x12 is valid"},
5177         {1, 0, 0, GL_NO_ERROR, "1: 0x0 is valid"},
5178         {1, 3, 3, GL_INVALID_OPERATION, "1: 3x3 is invalid"},
5179         {1, 5, 5, GL_INVALID_OPERATION, "1: 5x5 is invalid"},
5180         {1, 5, 6, GL_INVALID_OPERATION, "1: 5x6 is invalid"},
5181         {1, 6, 5, GL_INVALID_OPERATION, "1: 6x5 is invalid"},
5182         {1, 6, 6, GL_NO_ERROR, "1: 6x6 is valid"},
5183         {2, 0, 0, GL_NO_ERROR, "2: 0x0 is valid"},
5184         {2, 3, 3, GL_NO_ERROR, "2: 3x3 is valid"},
5185         {3, 1, 3, GL_NO_ERROR, "3: 1x3 is valid"},
5186         {3, 1, 1, GL_NO_ERROR, "3: 1x1 is valid"},
5187         {2, 1, 3, GL_NO_ERROR, "implied base mip 4x12 is valid"},
5188     };
5189 
5190     for (const TestCase &test : testCases)
5191     {
5192         testCompressedTexLevelDimension(format, test.level, test.width, test.height,
5193                                         expectedByteLength(format, test.width, test.height),
5194                                         test.expectedError, test.explanation);
5195     }
5196 
5197     if (getClientMajorVersion() >= 3)
5198     {
5199         for (const TestCase &test : webgl2TestCases)
5200         {
5201             testCompressedTexLevelDimension(format, test.level, test.width, test.height,
5202                                             expectedByteLength(format, test.width, test.height),
5203                                             test.expectedError, test.explanation);
5204         }
5205     }
5206 }
5207 
5208 // Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGB_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1RGB)5209 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGB)
5210 {
5211     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 8,
5212                                               "GL_EXT_texture_compression_dxt1", true);
5213 }
5214 
5215 // Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1RGBA)5216 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGBA)
5217 {
5218     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 8,
5219                                               "GL_EXT_texture_compression_dxt1", true);
5220 }
5221 
5222 // Test enabling GL_ANGLE_texture_compression_dxt3
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT3)5223 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT3)
5224 {
5225     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, 4, 4, 16,
5226                                               "GL_ANGLE_texture_compression_dxt3", true);
5227 }
5228 
5229 // Test enabling GL_ANGLE_texture_compression_dxt5
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT5)5230 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT5)
5231 {
5232     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, 4, 4, 16,
5233                                               "GL_ANGLE_texture_compression_dxt5", true);
5234 }
5235 
5236 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1SRGB)5237 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1SRGB)
5238 {
5239     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 4, 4, 8,
5240                                               "GL_EXT_texture_compression_s3tc_srgb", true);
5241 }
5242 
5243 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1SRGBA)5244 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1SRGBA)
5245 {
5246     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 4, 4, 8,
5247                                               "GL_EXT_texture_compression_s3tc_srgb", true);
5248 }
5249 
5250 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT3SRGBA)5251 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT3SRGBA)
5252 {
5253     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 4, 4, 16,
5254                                               "GL_EXT_texture_compression_s3tc_srgb", true);
5255 }
5256 
5257 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT5SRGBA)5258 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT5SRGBA)
5259 {
5260     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 4, 4, 16,
5261                                               "GL_EXT_texture_compression_s3tc_srgb", true);
5262 }
5263 
5264 // Test enabling GL_OES_compressed_ETC1_RGB8_texture
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionETC1)5265 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionETC1)
5266 {
5267     validateCompressedTexImageExtensionFormat(
5268         GL_ETC1_RGB8_OES, 4, 4, 8, "GL_OES_compressed_ETC1_RGB8_texture",
5269         IsGLExtensionEnabled("GL_EXT_compressed_ETC1_RGB8_sub_texture"));
5270 }
5271 
5272 // Test enabling GL_ANGLE_lossy_etc_decode
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionLossyDecode)5273 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionLossyDecode)
5274 {
5275     validateCompressedTexImageExtensionFormat(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 4, 4, 8,
5276                                               "GL_ANGLE_lossy_etc_decode", true);
5277 }
5278 
5279 // Reject attempts to allocate too-large arrays in shaders.
5280 // This is an implementation-defined limit - crbug.com/1220237 .
TEST_P(WebGLCompatibilityTest,ValidateArraySizes)5281 TEST_P(WebGLCompatibilityTest, ValidateArraySizes)
5282 {
5283     // Note: on macOS with ANGLE's OpenGL backend, getting anywhere
5284     // close to this limit causes pathologically slow shader
5285     // compilation in the driver. For the "ok" case, therefore, use a
5286     // fairly small array.
5287     constexpr char kVSArrayOK[] =
5288         R"(varying vec4 color;
5289 const int array_size = 500;
5290 void main()
5291 {
5292     mat2 array[array_size];
5293     mat2 array2[array_size];
5294     if (array[0][0][0] + array2[0][0][0] == 2.0)
5295         color = vec4(0.0, 1.0, 0.0, 1.0);
5296     else
5297         color = vec4(1.0, 0.0, 0.0, 1.0);
5298 })";
5299 
5300     constexpr char kVSArrayTooLarge[] =
5301         R"(varying vec4 color;
5302 // 16 MB / 32 aligned bytes per mat2 = 524288
5303 const int array_size = 524289;
5304 void main()
5305 {
5306     mat2 array[array_size];
5307     if (array[0][0][0] == 2.0)
5308         color = vec4(0.0, 1.0, 0.0, 1.0);
5309     else
5310         color = vec4(1.0, 0.0, 0.0, 1.0);
5311 })";
5312 
5313     constexpr char kVSArrayMuchTooLarge[] =
5314         R"(varying vec4 color;
5315 const int array_size = 757000;
5316 void main()
5317 {
5318     mat2 array[array_size];
5319     if (array[0][0][0] == 2.0)
5320         color = vec4(0.0, 1.0, 0.0, 1.0);
5321     else
5322         color = vec4(1.0, 0.0, 0.0, 1.0);
5323 })";
5324 
5325     constexpr char kFS[] =
5326         R"(precision mediump float;
5327 varying vec4 color;
5328 void main()
5329 {
5330     gl_FragColor = vec4(color.r - 0.5, 0.0, 0.0, 1.0);
5331 })";
5332 
5333     GLuint program = CompileProgram(kVSArrayOK, kFS);
5334     EXPECT_NE(0u, program);
5335 
5336     program = CompileProgram(kVSArrayTooLarge, kFS);
5337     EXPECT_EQ(0u, program);
5338 
5339     program = CompileProgram(kVSArrayMuchTooLarge, kFS);
5340     EXPECT_EQ(0u, program);
5341 }
5342 
5343 // Reject attempts to allocate too-large structs in shaders.
5344 // This is an implementation-defined limit - crbug.com/1220237 .
TEST_P(WebGLCompatibilityTest,ValidateStructSizes)5345 TEST_P(WebGLCompatibilityTest, ValidateStructSizes)
5346 {
5347     // Note: on macOS with ANGLE's OpenGL backend, getting anywhere
5348     // close to this limit causes pathologically slow shader
5349     // compilation in the driver. For this reason, only perform a
5350     // negative test.
5351     constexpr char kFSStructTooLarge[] =
5352         R"(precision mediump float;
5353 struct Light {
5354 // 2 GB / 32 aligned bytes per mat2 = 67108864
5355 mat2 array[67108865];
5356 };
5357 
5358 uniform Light light;
5359 
5360 void main()
5361 {
5362     if (light.array[0][0][0] == 2.0)
5363         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5364     else
5365         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5366 })";
5367 
5368     GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFSStructTooLarge);
5369     EXPECT_EQ(0u, program);
5370 
5371     // A second variation where the large array is on the variable itself not a member.
5372     constexpr char kFSStructTooLarge2[] =
5373         R"(precision mediump float;
5374 struct Light {
5375 mat2 array;
5376 };
5377 
5378 uniform Light light[67108865];
5379 
5380 void main()
5381 {
5382     if (light[0].array[0][0] == 2.0)
5383         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5384     else
5385         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5386 })";
5387 
5388     program = CompileProgram(essl1_shaders::vs::Simple(), kFSStructTooLarge2);
5389     EXPECT_EQ(0u, program);
5390 }
5391 
5392 // Reject attempts to allocate too much private memory.
5393 // This is an implementation-defined limit - crbug.com/1431761.
TEST_P(WebGLCompatibilityTest,ValidateTotalPrivateSize)5394 TEST_P(WebGLCompatibilityTest, ValidateTotalPrivateSize)
5395 {
5396     constexpr char kTooLargeGlobalMemory1[] =
5397         R"(precision mediump float;
5398 
5399 // 16 MB / 16 bytes per vec4 = 1048576
5400 vec4 array[524288];
5401 vec4 array2[524289];
5402 
5403 void main()
5404 {
5405     if (array[0].x + array[1].x == 0.)
5406         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5407     else
5408         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5409 })";
5410 
5411     constexpr char kTooLargeGlobalMemory2[] =
5412         R"(precision mediump float;
5413 
5414 // 16 MB / 16 bytes per vec4 = 1048576
5415 vec4 array[524287];
5416 vec4 array2[524287];
5417 vec4 x, y, z;
5418 
5419 void main()
5420 {
5421     if (array[0].x + array[1].x == x.w + y.w + z.w)
5422         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5423     else
5424         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5425 })";
5426 
5427     constexpr char kTooLargeGlobalAndLocalMemory1[] =
5428         R"(precision mediump float;
5429 
5430 // 16 MB / 16 bytes per vec4 = 1048576
5431 vec4 array[524288];
5432 
5433 void main()
5434 {
5435     vec4 array2[524289];
5436     if (array[0].x + array[1].x == 2.0)
5437         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5438     else
5439         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5440 })";
5441 
5442     // Note: The call stack is not taken into account for the purposes of total memory calculation.
5443     constexpr char kTooLargeGlobalAndLocalMemory2[] =
5444         R"(precision mediump float;
5445 
5446 // 16 MB / 16 bytes per vec4 = 1048576
5447 vec4 array[524288];
5448 
5449 float f()
5450 {
5451     vec4 array2[524288];
5452     return array2[0].x;
5453 }
5454 
5455 float g()
5456 {
5457     vec4 array3[524287];
5458     return array3[0].x;
5459 }
5460 
5461 float h()
5462 {
5463     vec4 value;
5464     float value2;
5465     return value.x + value2;
5466 }
5467 
5468 void main()
5469 {
5470     if (array[0].x + f() + g() + h() == 2.0)
5471         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5472     else
5473         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5474 })";
5475 
5476     constexpr char kTooLargeGlobalMemoryOverflow[] =
5477         R"(precision mediump float;
5478 
5479 // 16 MB / 16 bytes per vec4 = 1048576
5480 // Create 256 arrays so each is small, but the total overflows a 32-bit number
5481 vec4 array[1048576], array2[1048576], array3[1048576], array4[1048576], array5[1048576];
5482 vec4 array6[1048576], array7[1048576], array8[1048576], array9[1048576], array10[1048576];
5483 vec4 array11[1048576], array12[1048576], array13[1048576], array14[1048576], array15[1048576];
5484 vec4 array16[1048576], array17[1048576], array18[1048576], array19[1048576], array20[1048576];
5485 vec4 array21[1048576], array22[1048576], array23[1048576], array24[1048576], array25[1048576];
5486 vec4 array26[1048576], array27[1048576], array28[1048576], array29[1048576], array30[1048576];
5487 vec4 array31[1048576], array32[1048576], array33[1048576], array34[1048576], array35[1048576];
5488 vec4 array36[1048576], array37[1048576], array38[1048576], array39[1048576], array40[1048576];
5489 vec4 array41[1048576], array42[1048576], array43[1048576], array44[1048576], array45[1048576];
5490 vec4 array46[1048576], array47[1048576], array48[1048576], array49[1048576], array50[1048576];
5491 vec4 array51[1048576], array52[1048576], array53[1048576], array54[1048576], array55[1048576];
5492 vec4 array56[1048576], array57[1048576], array58[1048576], array59[1048576], array60[1048576];
5493 vec4 array61[1048576], array62[1048576], array63[1048576], array64[1048576], array65[1048576];
5494 vec4 array66[1048576], array67[1048576], array68[1048576], array69[1048576], array70[1048576];
5495 vec4 array71[1048576], array72[1048576], array73[1048576], array74[1048576], array75[1048576];
5496 vec4 array76[1048576], array77[1048576], array78[1048576], array79[1048576], array80[1048576];
5497 vec4 array81[1048576], array82[1048576], array83[1048576], array84[1048576], array85[1048576];
5498 vec4 array86[1048576], array87[1048576], array88[1048576], array89[1048576], array90[1048576];
5499 vec4 array91[1048576], array92[1048576], array93[1048576], array94[1048576], array95[1048576];
5500 vec4 array96[1048576], array97[1048576], array98[1048576], array99[1048576], array100[1048576];
5501 vec4 array101[1048576], array102[1048576], array103[1048576], array104[1048576], array105[1048576];
5502 vec4 array106[1048576], array107[1048576], array108[1048576], array109[1048576], array110[1048576];
5503 vec4 array111[1048576], array112[1048576], array113[1048576], array114[1048576], array115[1048576];
5504 vec4 array116[1048576], array117[1048576], array118[1048576], array119[1048576], array120[1048576];
5505 vec4 array121[1048576], array122[1048576], array123[1048576], array124[1048576], array125[1048576];
5506 vec4 array126[1048576], array127[1048576], array128[1048576], array129[1048576], array130[1048576];
5507 vec4 array131[1048576], array132[1048576], array133[1048576], array134[1048576], array135[1048576];
5508 vec4 array136[1048576], array137[1048576], array138[1048576], array139[1048576], array140[1048576];
5509 vec4 array141[1048576], array142[1048576], array143[1048576], array144[1048576], array145[1048576];
5510 vec4 array146[1048576], array147[1048576], array148[1048576], array149[1048576], array150[1048576];
5511 vec4 array151[1048576], array152[1048576], array153[1048576], array154[1048576], array155[1048576];
5512 vec4 array156[1048576], array157[1048576], array158[1048576], array159[1048576], array160[1048576];
5513 vec4 array161[1048576], array162[1048576], array163[1048576], array164[1048576], array165[1048576];
5514 vec4 array166[1048576], array167[1048576], array168[1048576], array169[1048576], array170[1048576];
5515 vec4 array171[1048576], array172[1048576], array173[1048576], array174[1048576], array175[1048576];
5516 vec4 array176[1048576], array177[1048576], array178[1048576], array179[1048576], array180[1048576];
5517 vec4 array181[1048576], array182[1048576], array183[1048576], array184[1048576], array185[1048576];
5518 vec4 array186[1048576], array187[1048576], array188[1048576], array189[1048576], array190[1048576];
5519 vec4 array191[1048576], array192[1048576], array193[1048576], array194[1048576], array195[1048576];
5520 vec4 array196[1048576], array197[1048576], array198[1048576], array199[1048576], array200[1048576];
5521 vec4 array201[1048576], array202[1048576], array203[1048576], array204[1048576], array205[1048576];
5522 vec4 array206[1048576], array207[1048576], array208[1048576], array209[1048576], array210[1048576];
5523 vec4 array211[1048576], array212[1048576], array213[1048576], array214[1048576], array215[1048576];
5524 vec4 array216[1048576], array217[1048576], array218[1048576], array219[1048576], array220[1048576];
5525 vec4 array221[1048576], array222[1048576], array223[1048576], array224[1048576], array225[1048576];
5526 vec4 array226[1048576], array227[1048576], array228[1048576], array229[1048576], array230[1048576];
5527 vec4 array231[1048576], array232[1048576], array233[1048576], array234[1048576], array235[1048576];
5528 vec4 array236[1048576], array237[1048576], array238[1048576], array239[1048576], array240[1048576];
5529 vec4 array241[1048576], array242[1048576], array243[1048576], array244[1048576], array245[1048576];
5530 vec4 array246[1048576], array247[1048576], array248[1048576], array249[1048576], array250[1048576];
5531 vec4 array251[1048576], array252[1048576], array253[1048576], array254[1048576], array255[1048576];
5532 vec4 array256[1048576];
5533 
5534 void main()
5535 {
5536     float f = array[0].x; f += array2[0].x; f += array3[0].x; f += array4[0].x; f += array5[0].x;
5537     f += array6[0].x; f += array7[0].x; f += array8[0].x; f += array9[0].x; f += array10[0].x;
5538     f += array11[0].x; f += array12[0].x; f += array13[0].x; f += array14[0].x; f += array15[0].x;
5539     f += array16[0].x; f += array17[0].x; f += array18[0].x; f += array19[0].x; f += array20[0].x;
5540     f += array21[0].x; f += array22[0].x; f += array23[0].x; f += array24[0].x; f += array25[0].x;
5541     f += array26[0].x; f += array27[0].x; f += array28[0].x; f += array29[0].x; f += array30[0].x;
5542     f += array31[0].x; f += array32[0].x; f += array33[0].x; f += array34[0].x; f += array35[0].x;
5543     f += array36[0].x; f += array37[0].x; f += array38[0].x; f += array39[0].x; f += array40[0].x;
5544     f += array41[0].x; f += array42[0].x; f += array43[0].x; f += array44[0].x; f += array45[0].x;
5545     f += array46[0].x; f += array47[0].x; f += array48[0].x; f += array49[0].x; f += array50[0].x;
5546     f += array51[0].x; f += array52[0].x; f += array53[0].x; f += array54[0].x; f += array55[0].x;
5547     f += array56[0].x; f += array57[0].x; f += array58[0].x; f += array59[0].x; f += array60[0].x;
5548     f += array61[0].x; f += array62[0].x; f += array63[0].x; f += array64[0].x; f += array65[0].x;
5549     f += array66[0].x; f += array67[0].x; f += array68[0].x; f += array69[0].x; f += array70[0].x;
5550     f += array71[0].x; f += array72[0].x; f += array73[0].x; f += array74[0].x; f += array75[0].x;
5551     f += array76[0].x; f += array77[0].x; f += array78[0].x; f += array79[0].x; f += array80[0].x;
5552     f += array81[0].x; f += array82[0].x; f += array83[0].x; f += array84[0].x; f += array85[0].x;
5553     f += array86[0].x; f += array87[0].x; f += array88[0].x; f += array89[0].x; f += array90[0].x;
5554     f += array91[0].x; f += array92[0].x; f += array93[0].x; f += array94[0].x; f += array95[0].x;
5555     f += array96[0].x; f += array97[0].x; f += array98[0].x; f += array99[0].x; f += array100[0].x;
5556     f += array101[0].x; f += array102[0].x; f += array103[0].x; f += array104[0].x;
5557     f += array105[0].x; f += array106[0].x; f += array107[0].x; f += array108[0].x;
5558     f += array109[0].x; f += array110[0].x; f += array111[0].x; f += array112[0].x;
5559     f += array113[0].x; f += array114[0].x; f += array115[0].x; f += array116[0].x;
5560     f += array117[0].x; f += array118[0].x; f += array119[0].x; f += array120[0].x;
5561     f += array121[0].x; f += array122[0].x; f += array123[0].x; f += array124[0].x;
5562     f += array125[0].x; f += array126[0].x; f += array127[0].x; f += array128[0].x;
5563     f += array129[0].x; f += array130[0].x; f += array131[0].x; f += array132[0].x;
5564     f += array133[0].x; f += array134[0].x; f += array135[0].x; f += array136[0].x;
5565     f += array137[0].x; f += array138[0].x; f += array139[0].x; f += array140[0].x;
5566     f += array141[0].x; f += array142[0].x; f += array143[0].x; f += array144[0].x;
5567     f += array145[0].x; f += array146[0].x; f += array147[0].x; f += array148[0].x;
5568     f += array149[0].x; f += array150[0].x; f += array151[0].x; f += array152[0].x;
5569     f += array153[0].x; f += array154[0].x; f += array155[0].x; f += array156[0].x;
5570     f += array157[0].x; f += array158[0].x; f += array159[0].x; f += array160[0].x;
5571     f += array161[0].x; f += array162[0].x; f += array163[0].x; f += array164[0].x;
5572     f += array165[0].x; f += array166[0].x; f += array167[0].x; f += array168[0].x;
5573     f += array169[0].x; f += array170[0].x; f += array171[0].x; f += array172[0].x;
5574     f += array173[0].x; f += array174[0].x; f += array175[0].x; f += array176[0].x;
5575     f += array177[0].x; f += array178[0].x; f += array179[0].x; f += array180[0].x;
5576     f += array181[0].x; f += array182[0].x; f += array183[0].x; f += array184[0].x;
5577     f += array185[0].x; f += array186[0].x; f += array187[0].x; f += array188[0].x;
5578     f += array189[0].x; f += array190[0].x; f += array191[0].x; f += array192[0].x;
5579     f += array193[0].x; f += array194[0].x; f += array195[0].x; f += array196[0].x;
5580     f += array197[0].x; f += array198[0].x; f += array199[0].x; f += array200[0].x;
5581     f += array201[0].x; f += array202[0].x; f += array203[0].x; f += array204[0].x;
5582     f += array205[0].x; f += array206[0].x; f += array207[0].x; f += array208[0].x;
5583     f += array209[0].x; f += array210[0].x; f += array211[0].x; f += array212[0].x;
5584     f += array213[0].x; f += array214[0].x; f += array215[0].x; f += array216[0].x;
5585     f += array217[0].x; f += array218[0].x; f += array219[0].x; f += array220[0].x;
5586     f += array221[0].x; f += array222[0].x; f += array223[0].x; f += array224[0].x;
5587     f += array225[0].x; f += array226[0].x; f += array227[0].x; f += array228[0].x;
5588     f += array229[0].x; f += array230[0].x; f += array231[0].x; f += array232[0].x;
5589     f += array233[0].x; f += array234[0].x; f += array235[0].x; f += array236[0].x;
5590     f += array237[0].x; f += array238[0].x; f += array239[0].x; f += array240[0].x;
5591     f += array241[0].x; f += array242[0].x; f += array243[0].x; f += array244[0].x;
5592     f += array245[0].x; f += array246[0].x; f += array247[0].x; f += array248[0].x;
5593     f += array249[0].x; f += array250[0].x; f += array251[0].x; f += array252[0].x;
5594     f += array253[0].x; f += array254[0].x; f += array255[0].x; f += array256[0].x;
5595     if (f == 2.0)
5596         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5597     else
5598         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5599 })";
5600 
5601     GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1);
5602     EXPECT_EQ(0u, program);
5603 
5604     program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory2);
5605     EXPECT_EQ(0u, program);
5606 
5607     program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory1);
5608     EXPECT_EQ(0u, program);
5609 
5610     program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
5611     EXPECT_EQ(0u, program);
5612 
5613     program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemoryOverflow);
5614     EXPECT_EQ(0u, program);
5615 }
5616 
5617 // Linking should fail when corresponding vertex/fragment uniform blocks have different precision
5618 // qualifiers.
TEST_P(WebGL2CompatibilityTest,UniformBlockPrecisionMismatch)5619 TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
5620 {
5621     constexpr char kVS[] =
5622         R"(#version 300 es
5623 uniform Block { mediump vec4 val; };
5624 void main() { gl_Position = val; })";
5625     constexpr char kFS[] =
5626         R"(#version 300 es
5627 uniform Block { highp vec4 val; };
5628 out highp vec4 out_FragColor;
5629 void main() { out_FragColor = val; })";
5630 
5631     GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
5632     ASSERT_NE(0u, vs);
5633     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
5634     ASSERT_NE(0u, fs);
5635 
5636     GLuint program = glCreateProgram();
5637 
5638     glAttachShader(program, vs);
5639     glDeleteShader(vs);
5640     glAttachShader(program, fs);
5641     glDeleteShader(fs);
5642 
5643     glLinkProgram(program);
5644     GLint linkStatus;
5645     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
5646     ASSERT_EQ(0, linkStatus);
5647 
5648     glDeleteProgram(program);
5649 }
5650 
5651 // Test no attribute vertex shaders
TEST_P(WebGL2CompatibilityTest,NoAttributeVertexShader)5652 TEST_P(WebGL2CompatibilityTest, NoAttributeVertexShader)
5653 {
5654     constexpr char kVS[] =
5655         R"(#version 300 es
5656 void main()
5657 {
5658 
5659     ivec2 xy = ivec2(gl_VertexID % 2, (gl_VertexID / 2 + gl_VertexID / 3) % 2);
5660     gl_Position = vec4(vec2(xy) * 2. - 1., 0, 1);
5661 })";
5662 
5663     ANGLE_GL_PROGRAM(program, kVS, essl3_shaders::fs::Red());
5664     glUseProgram(program);
5665 
5666     glDrawArrays(GL_TRIANGLES, 0, 6);
5667     ASSERT_GL_NO_ERROR();
5668     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
5669 }
5670 
5671 // Tests bindAttribLocations for length limit
TEST_P(WebGL2CompatibilityTest,BindAttribLocationLimitation)5672 TEST_P(WebGL2CompatibilityTest, BindAttribLocationLimitation)
5673 {
5674     constexpr int maxLocStringLength = 1024;
5675     const std::string tooLongString(maxLocStringLength + 1, '_');
5676 
5677     glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
5678 
5679     EXPECT_GL_ERROR(GL_INVALID_VALUE);
5680 }
5681 
5682 // Tests getAttribLocation for length limit
TEST_P(WebGL2CompatibilityTest,GetAttribLocationLengthLimitation)5683 TEST_P(WebGL2CompatibilityTest, GetAttribLocationLengthLimitation)
5684 {
5685     constexpr int maxLocStringLength = 1024;
5686     const std::string tooLongString(maxLocStringLength + 1, '_');
5687 
5688     glGetAttribLocation(0, static_cast<const GLchar *>(tooLongString.c_str()));
5689 
5690     EXPECT_GL_ERROR(GL_INVALID_VALUE);
5691 }
5692 
5693 // Covers a bug in transform feedback loop detection.
TEST_P(WebGL2CompatibilityTest,TransformFeedbackCheckNullDeref)5694 TEST_P(WebGL2CompatibilityTest, TransformFeedbackCheckNullDeref)
5695 {
5696     constexpr char kVS[] = R"(attribute vec4 color; void main() { color.r; })";
5697     constexpr char kFS[] = R"(void main(){})";
5698     ANGLE_GL_PROGRAM(program, kVS, kFS);
5699     glUseProgram(program);
5700 
5701     glEnableVertexAttribArray(0);
5702     glDrawArrays(GL_POINTS, 0, 1);
5703 
5704     // This should fail because it is trying to pull a vertex with no buffer.
5705     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5706 
5707     GLBuffer buffer;
5708     glBindBuffer(GL_ARRAY_BUFFER, buffer);
5709     glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
5710 
5711     // This should fail because it is trying to pull a vertex from an empty buffer.
5712     glDrawArrays(GL_POINTS, 0, 1);
5713     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5714 }
5715 
5716 // We should forbid two transform feedback outputs going to the same buffer.
TEST_P(WebGL2CompatibilityTest,TransformFeedbackDoubleBinding)5717 TEST_P(WebGL2CompatibilityTest, TransformFeedbackDoubleBinding)
5718 {
5719     constexpr char kVS[] =
5720         R"(attribute float a; varying float b; varying float c; void main() { b = a; c = a; })";
5721     constexpr char kFS[] = R"(void main(){})";
5722     ANGLE_GL_PROGRAM(program, kVS, kFS);
5723     static const char *varyings[] = {"b", "c"};
5724     glTransformFeedbackVaryings(program, 2, varyings, GL_SEPARATE_ATTRIBS);
5725     glLinkProgram(program);
5726     glUseProgram(program);
5727     ASSERT_GL_NO_ERROR();
5728 
5729     // Bind the transform feedback varyings to non-overlapping regions of the same buffer.
5730     GLBuffer buffer;
5731     glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer, 0, 4);
5732     glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, buffer, 4, 4);
5733     glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 8, nullptr, GL_STATIC_DRAW);
5734     ASSERT_GL_NO_ERROR();
5735     // Two varyings bound to the same buffer should be an error.
5736     glBeginTransformFeedback(GL_POINTS);
5737     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5738 }
5739 
5740 // Check the return type of a given parameter upon getting the active uniforms.
TEST_P(WebGL2CompatibilityTest,UniformVariablesReturnTypes)5741 TEST_P(WebGL2CompatibilityTest, UniformVariablesReturnTypes)
5742 {
5743     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
5744 
5745     std::vector<GLuint> validUniformIndices = {0};
5746     std::vector<GLint> uniformNameLengthBuf(validUniformIndices.size());
5747 
5748     // This should fail because GL_UNIFORM_NAME_LENGTH cannot be used in WebGL2.
5749     glGetActiveUniformsiv(program, static_cast<GLsizei>(validUniformIndices.size()),
5750                           &validUniformIndices[0], GL_UNIFORM_NAME_LENGTH,
5751                           &uniformNameLengthBuf[0]);
5752     EXPECT_GL_ERROR(GL_INVALID_ENUM);
5753 }
5754 
5755 // Tests an error case to ensure we don't crash.
TEST_P(WebGLCompatibilityTest,DrawWithNoProgram)5756 TEST_P(WebGLCompatibilityTest, DrawWithNoProgram)
5757 {
5758     glDrawArrays(GL_TRIANGLES, 0, 6);
5759     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5760 }
5761 
5762 // Ensures that rendering to different texture levels of a sampled texture is supported.
TEST_P(WebGL2CompatibilityTest,RenderToLevelsOfSampledTexture)5763 TEST_P(WebGL2CompatibilityTest, RenderToLevelsOfSampledTexture)
5764 {
5765     // TODO: Fix on Vulkan back-end. http://anglebug.com/40644733
5766     ANGLE_SKIP_TEST_IF(IsVulkan());
5767 
5768     constexpr GLsizei kTexSize   = 2;
5769     constexpr GLsizei kTexLevels = 2;
5770 
5771     std::vector<GLColor> texData(kTexSize * kTexSize, GLColor::green);
5772 
5773     GLTexture sourceTexture;
5774     glBindTexture(GL_TEXTURE_2D, sourceTexture);
5775     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5776     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5777     glTexStorage2D(GL_TEXTURE_2D, kTexLevels, GL_RGBA8, kTexSize, kTexSize);
5778     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, GL_RGBA, GL_UNSIGNED_BYTE,
5779                     texData.data());
5780 
5781     GLFramebuffer fbo;
5782     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
5783     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 1);
5784     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
5785     glViewport(0, 0, kTexSize / 2, kTexSize / 2);
5786 
5787     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
5788     ASSERT_GL_NO_ERROR();
5789 
5790     // Should work - drawing from level 0 to level 1.
5791     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5792     EXPECT_GL_NO_ERROR();
5793     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
5794 
5795     // Should not work - drawing from levels [0,1] to level 1.
5796     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
5797     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5798     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5799 
5800     // Should work - drawing with levels [0,1] to default FBO.
5801     glBindFramebuffer(GL_FRAMEBUFFER, 0);
5802     glViewport(0, 0, getWindowWidth(), getWindowHeight());
5803 
5804     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5805     EXPECT_GL_NO_ERROR();
5806     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
5807 }
5808 
5809 // Reject attempts to allocate too-large variables in shaders.
5810 // This is an implementation-defined limit - crbug.com/1220237 .
TEST_P(WebGL2CompatibilityTest,ValidateTypeSizes)5811 TEST_P(WebGL2CompatibilityTest, ValidateTypeSizes)
5812 {
5813     constexpr char kFSArrayBlockTooLarge[] = R"(#version 300 es
5814 precision mediump float;
5815 // 1 + the maximum size this implementation allows.
5816 uniform LargeArrayBlock {
5817     vec4 large_array[134217729];
5818 };
5819 
5820 out vec4 out_FragColor;
5821 
5822 void main()
5823 {
5824     if (large_array[1].x == 2.0)
5825         out_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5826     else
5827         out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5828 }
5829 )";
5830 
5831     GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFSArrayBlockTooLarge);
5832     EXPECT_EQ(0u, program);
5833 }
5834 
5835 // Ensure that new type size validation code added for
5836 // crbug.com/1220237 does not crash.
TEST_P(WebGL2CompatibilityTest,ValidatingTypeSizesShouldNotCrash)5837 TEST_P(WebGL2CompatibilityTest, ValidatingTypeSizesShouldNotCrash)
5838 {
5839     constexpr char kFS1[] = R"(#version 300 es
5840 precision mediump float;
5841 out vec4 my_FragColor;
5842 
5843 const vec4 constants[2] = vec4[] (
5844     vec4(0.6, 0.3, 0.0, 3.0),
5845     vec4(-0.6, 0.7, 0.0, -2.0)
5846 );
5847 
5848 void main()
5849 {
5850     my_FragColor = constants[0] + constants[1];
5851     return;
5852 })";
5853 
5854     constexpr char kFS2[] = R"(#version 300 es
5855 precision mediump float;
5856 out vec4 my_FragColor;
5857 
5858 const vec4 constants[2] = vec4[] (
5859     vec4(0.6, 0.3, 0.0, 3.0),
5860     vec4(-0.6, 0.7, 0.0, -2.0)
5861 );
5862 
5863 const vec4 constants2[2] = vec4[] (
5864     constants[1],
5865     constants[0]
5866 );
5867 
5868 void main()
5869 {
5870     my_FragColor = constants2[0] + constants2[1];
5871     return;
5872 })";
5873 
5874     constexpr char kFS3[] = R"(#version 300 es
5875 precision mediump float;
5876 out vec4 my_FragColor;
5877 
5878 const vec4 constants[2] = vec4[] (
5879     vec4(0.6, 0.3, 0.0, 3.0),
5880     vec4(-0.6, 0.7, 0.0, -2.0)
5881 );
5882 
5883 const vec4 constants2[2] = constants;
5884 
5885 void main()
5886 {
5887     my_FragColor = constants2[0] + constants2[1];
5888     return;
5889 })";
5890 
5891     GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFS1);
5892     EXPECT_NE(0u, program);
5893 
5894     program = CompileProgram(essl3_shaders::vs::Simple(), kFS2);
5895     EXPECT_NE(0u, program);
5896 
5897     program = CompileProgram(essl3_shaders::vs::Simple(), kFS3);
5898     EXPECT_NE(0u, program);
5899 }
5900 
5901 // Verify glReadPixels will accept GL_RGBX8_ANGLE + GL_UNSIGNED_BYTE.
TEST_P(WebGL2CompatibilityTest,ReadPixelsRgbx8AngleUnsignedByte)5902 TEST_P(WebGL2CompatibilityTest, ReadPixelsRgbx8AngleUnsignedByte)
5903 {
5904     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_rgbx_internal_format"));
5905 
5906     GLFramebuffer fb;
5907     glBindFramebuffer(GL_FRAMEBUFFER, fb);
5908 
5909     GLTexture tex;
5910     glBindTexture(GL_TEXTURE_2D, tex);
5911     glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBX8_ANGLE, 1, 1);
5912     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5913     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5914 
5915     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
5916     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
5917 
5918     glBindFramebuffer(GL_FRAMEBUFFER, 0);
5919 
5920     glClearColor(1.0, 0.0, 0.0, 1.0);
5921     glClear(GL_COLOR_BUFFER_BIT);
5922     ASSERT_GL_NO_ERROR();
5923 
5924     GLColor pixel;
5925     glReadPixels(0, 0, 1, 1, GL_RGBX8_ANGLE, GL_UNSIGNED_BYTE, &pixel.R);
5926     ASSERT_GL_NO_ERROR();
5927 
5928     EXPECT_EQ(GLColor::red, pixel);
5929 }
5930 
5931 // Test that masked-out draw attachments do not require fragment outputs.
TEST_P(WebGL2CompatibilityTest,DrawWithMaskedOutAttachments)5932 TEST_P(WebGL2CompatibilityTest, DrawWithMaskedOutAttachments)
5933 {
5934     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
5935 
5936     GLFramebuffer fbo;
5937     GLRenderbuffer rbo[2];
5938     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
5939 
5940     glBindRenderbuffer(GL_RENDERBUFFER, rbo[0]);
5941     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
5942     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[0]);
5943 
5944     glBindRenderbuffer(GL_RENDERBUFFER, rbo[1]);
5945     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
5946     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rbo[1]);
5947 
5948     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
5949 
5950     constexpr char kFS[] = R"(#version 300 es
5951 precision highp float;
5952 
5953 layout(location = 0) out vec4 color;
5954 
5955 void main()
5956 {
5957     color = vec4(1.0, 1.0, 1.0, 1.0);
5958 }
5959 )";
5960 
5961     ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
5962     glUseProgram(program);
5963 
5964     GLenum bufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
5965     glDrawBuffers(2, bufs);
5966 
5967     // Error: no fragment output for attachment1
5968     drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5969     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5970 
5971     // No error: attachment1 is masked-out
5972     glColorMaskiOES(1, false, false, false, false);
5973     drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5974     EXPECT_GL_NO_ERROR();
5975 }
5976 
5977 // Test that ETC2/EAC formats are rejected by unextended WebGL 2.0 contexts.
TEST_P(WebGL2CompatibilityTest,ETC2EACFormats)5978 TEST_P(WebGL2CompatibilityTest, ETC2EACFormats)
5979 {
5980     size_t byteLength          = 8;
5981     constexpr uint8_t data[16] = {};
5982     constexpr GLenum formats[] = {GL_COMPRESSED_R11_EAC,
5983                                   GL_COMPRESSED_SIGNED_R11_EAC,
5984                                   GL_COMPRESSED_RGB8_ETC2,
5985                                   GL_COMPRESSED_SRGB8_ETC2,
5986                                   GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
5987                                   GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
5988                                   GL_COMPRESSED_RG11_EAC,
5989                                   GL_COMPRESSED_SIGNED_RG11_EAC,
5990                                   GL_COMPRESSED_RGBA8_ETC2_EAC,
5991                                   GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC};
5992 
5993     for (const auto &fmt : formats)
5994     {
5995         if (fmt == GL_COMPRESSED_RG11_EAC)
5996             byteLength = 16;
5997 
5998         {
5999             GLTexture tex;
6000             glBindTexture(GL_TEXTURE_2D, tex);
6001             glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, 4, 4, 0, byteLength, data);
6002             EXPECT_GL_ERROR(GL_INVALID_ENUM);
6003         }
6004 
6005         {
6006             GLTexture tex;
6007             glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
6008             glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, fmt, 4, 4, 1, 0, byteLength, data);
6009             EXPECT_GL_ERROR(GL_INVALID_ENUM);
6010         }
6011 
6012         {
6013             GLTexture tex;
6014             glBindTexture(GL_TEXTURE_2D, tex);
6015             glTexStorage2D(GL_TEXTURE_2D, 1, fmt, 4, 4);
6016             EXPECT_GL_ERROR(GL_INVALID_ENUM);
6017         }
6018 
6019         {
6020             GLTexture tex;
6021             glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
6022             glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, fmt, 4, 4, 1);
6023             EXPECT_GL_ERROR(GL_INVALID_ENUM);
6024         }
6025     }
6026 }
6027 
6028 // Test that GL_HALF_FLOAT_OES type is rejected by WebGL 2.0 contexts.
TEST_P(WebGL2CompatibilityTest,HalfFloatOesType)6029 TEST_P(WebGL2CompatibilityTest, HalfFloatOesType)
6030 {
6031     const std::array<std::pair<GLenum, GLenum>, 6> formats = {{{GL_R16F, GL_RED},
6032                                                                {GL_RG16F, GL_RG},
6033                                                                {GL_RGB16F, GL_RGB},
6034                                                                {GL_RGBA16F, GL_RGBA},
6035                                                                {GL_R11F_G11F_B10F, GL_RGB},
6036                                                                {GL_RGB9_E5, GL_RGB}}};
6037     for (const auto &fmt : formats)
6038     {
6039         {
6040             GLTexture tex;
6041             glBindTexture(GL_TEXTURE_2D, tex);
6042             EXPECT_GL_NO_ERROR();
6043 
6044             glTexImage2D(GL_TEXTURE_2D, 0, fmt.first, 1, 1, 0, fmt.second, GL_HALF_FLOAT_OES,
6045                          nullptr);
6046             EXPECT_GL_ERROR(GL_INVALID_ENUM);
6047 
6048             glTexImage2D(GL_TEXTURE_2D, 0, fmt.first, 1, 1, 0, fmt.second, GL_HALF_FLOAT, nullptr);
6049             EXPECT_GL_NO_ERROR();
6050         }
6051         {
6052             GLTexture tex;
6053             glBindTexture(GL_TEXTURE_3D, tex);
6054             EXPECT_GL_NO_ERROR();
6055 
6056             glTexImage3D(GL_TEXTURE_3D, 0, fmt.first, 1, 1, 1, 0, fmt.second, GL_HALF_FLOAT_OES,
6057                          nullptr);
6058             EXPECT_GL_ERROR(GL_INVALID_ENUM);
6059 
6060             glTexImage3D(GL_TEXTURE_3D, 0, fmt.first, 1, 1, 1, 0, fmt.second, GL_HALF_FLOAT,
6061                          nullptr);
6062             EXPECT_GL_NO_ERROR();
6063         }
6064     }
6065 }
6066 
6067 // Test that unsigned integer samplers work with stencil textures.
TEST_P(WebGL2CompatibilityTest,StencilTexturingStencil8)6068 TEST_P(WebGL2CompatibilityTest, StencilTexturingStencil8)
6069 {
6070     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_stencil8"));
6071 
6072     const uint8_t stencilValue = 42;
6073     GLTexture tex;
6074     glBindTexture(GL_TEXTURE_2D, tex);
6075     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6076     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6077     glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX8, 1, 1, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
6078                  &stencilValue);
6079     ASSERT_GL_NO_ERROR();
6080 
6081     constexpr char kFS[] = R"(#version 300 es
6082 out mediump vec4 color;
6083 uniform mediump usampler2D tex;
6084 void main() {
6085     color = vec4(vec3(texture(tex, vec2(0.0, 0.0))) / 255.0, 1.0);
6086 })";
6087     ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
6088 
6089     drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6090     EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(42, 0, 0, 255), 1);
6091 }
6092 
6093 // Test that unsigned integer samplers work with combined depth/stencil textures.
TEST_P(WebGL2CompatibilityTest,StencilTexturingCombined)6094 TEST_P(WebGL2CompatibilityTest, StencilTexturingCombined)
6095 {
6096     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_stencil_texturing"));
6097 
6098     const uint32_t stencilValue = 42;
6099     GLTexture tex;
6100     glBindTexture(GL_TEXTURE_2D, tex);
6101     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6102     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6103     glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE_ANGLE, GL_STENCIL_INDEX);
6104     glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 1, 1, 0, GL_DEPTH_STENCIL,
6105                  GL_UNSIGNED_INT_24_8, &stencilValue);
6106     ASSERT_GL_NO_ERROR();
6107 
6108     constexpr char kFS[] = R"(#version 300 es
6109 out mediump vec4 color;
6110 uniform mediump usampler2D tex;
6111 void main() {
6112     color = vec4(vec3(texture(tex, vec2(0.0, 0.0))) / 255.0, 1.0);
6113 })";
6114     ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
6115 
6116     drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6117     EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(42, 0, 0, 255), 1);
6118 }
6119 
6120 // Regression test for syncing internal state for TexImage calls while there is an incomplete
6121 // framebuffer bound
TEST_P(WebGL2CompatibilityTest,TexImageSyncWithIncompleteFramebufferBug)6122 TEST_P(WebGL2CompatibilityTest, TexImageSyncWithIncompleteFramebufferBug)
6123 {
6124     glColorMask(false, true, false, false);
6125     glClear(GL_COLOR_BUFFER_BIT);
6126     glViewport(100, 128, 65, 65537);
6127 
6128     GLFramebuffer fb1;
6129     glBindFramebuffer(GL_FRAMEBUFFER, fb1);
6130 
6131     GLRenderbuffer rb;
6132     glBindRenderbuffer(GL_RENDERBUFFER, rb);
6133     glRenderbufferStorage(GL_RENDERBUFFER, GL_RG8UI, 1304, 2041);
6134     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb);
6135 
6136     GLTexture texture;
6137     glBindTexture(GL_TEXTURE_2D, texture);
6138     glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 8, 8, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, nullptr);
6139 }
6140 
6141 // Test that "depth_unchanged" layout qualifier is rejected for WebGL contexts.
TEST_P(WebGL2CompatibilityTest,FragDepthLayoutUnchanged)6142 TEST_P(WebGL2CompatibilityTest, FragDepthLayoutUnchanged)
6143 {
6144     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_conservative_depth"));
6145 
6146     constexpr char kFS[] = R"(#version 300 es
6147 #extension GL_EXT_conservative_depth: enable
6148 out highp vec4 color;
6149 layout (depth_unchanged) out highp float gl_FragDepth;
6150 void main() {
6151     color = vec4(0.0, 0.0, 0.0, 1.0);
6152     gl_FragDepth = 1.0;
6153 })";
6154 
6155     GLProgram prg;
6156     prg.makeRaster(essl3_shaders::vs::Simple(), kFS);
6157     EXPECT_FALSE(prg.valid());
6158 }
6159 
6160 // Test that EXT_blend_func_extended does not allow omitting locations in WebGL 2.0 contexts.
TEST_P(WebGL2CompatibilityTest,EXTBlendFuncExtendedNoLocations)6161 TEST_P(WebGL2CompatibilityTest, EXTBlendFuncExtendedNoLocations)
6162 {
6163     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
6164 
6165     constexpr char kFS[] = R"(#version 300 es
6166 #extension GL_EXT_blend_func_extended : require
6167 out highp vec4 color0;
6168 out highp vec4 color1;
6169 void main() {
6170     color0 = vec4(1.0, 0.0, 0.0, 1.0);
6171     color1 = vec4(0.0, 1.0, 0.0, 1.0);
6172 })";
6173 
6174     GLProgram prg;
6175     prg.makeRaster(essl3_shaders::vs::Simple(), kFS);
6176     EXPECT_FALSE(prg.valid());
6177 }
6178 
6179 // Test that fragment outputs may be omitted when enabling
6180 // SRC1 blend functions with all color channels masked out.
TEST_P(WebGLCompatibilityTest,EXTBlendFuncExtendedMissingOutputsWithAllChannelsMaskedOut)6181 TEST_P(WebGLCompatibilityTest, EXTBlendFuncExtendedMissingOutputsWithAllChannelsMaskedOut)
6182 {
6183     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
6184 
6185     glEnable(GL_BLEND);
6186     glBlendFunc(GL_ONE, GL_SRC1_COLOR_EXT);
6187     glColorMask(false, false, false, false);
6188 
6189     // Secondary output missing
6190     {
6191         constexpr char kFragColor[] = R"(
6192             void main() {
6193                 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
6194             })";
6195         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFragColor);
6196         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0, true);
6197         EXPECT_GL_NO_ERROR();
6198     }
6199 
6200     // Primary output missing
6201     {
6202         constexpr char kSecondaryFragColor[] = R"(#extension GL_EXT_blend_func_extended : enable
6203             void main() {
6204                 gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0);
6205             })";
6206         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kSecondaryFragColor);
6207         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0, true);
6208         EXPECT_GL_NO_ERROR();
6209     }
6210 
6211     // Both outputs missing
6212     {
6213         constexpr char kNone[] = "void main() {}";
6214         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kNone);
6215         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0, true);
6216         EXPECT_GL_NO_ERROR();
6217     }
6218 }
6219 
6220 // Test that both fragment outputs must be statically used
6221 // when enabling SRC1 blend functions in WebGL 1.0 contexts.
TEST_P(WebGLCompatibilityTest,EXTBlendFuncExtendedMissingOutputs)6222 TEST_P(WebGLCompatibilityTest, EXTBlendFuncExtendedMissingOutputs)
6223 {
6224     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
6225 
6226     glEnable(GL_BLEND);
6227     glBlendFunc(GL_ONE, GL_SRC1_COLOR_EXT);
6228     ASSERT_GL_NO_ERROR();
6229 
6230     {
6231         constexpr char kFragColor[] = R"(
6232 void main() {
6233     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
6234 })";
6235         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFragColor);
6236         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6237         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6238     }
6239     {
6240         constexpr char kSecondaryFragColor[] = R"(#extension GL_EXT_blend_func_extended : require
6241 void main() {
6242     gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0);
6243 })";
6244         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kSecondaryFragColor);
6245         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6246         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6247     }
6248     {
6249         constexpr char kFragColorAndSecondaryFragColor[] =
6250             R"(#extension GL_EXT_blend_func_extended : require
6251 void main() {
6252     gl_FragColor             = vec4(1.0, 0.0, 0.0, 1.0);
6253     gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0);
6254 })";
6255         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFragColorAndSecondaryFragColor);
6256         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6257         ASSERT_GL_NO_ERROR();
6258     }
6259 }
6260 
6261 // Test that both fragment outputs must be statically used
6262 // when enabling SRC1 blend functions in WebGL 1.0 contexts.
TEST_P(WebGLCompatibilityTest,EXTBlendFuncExtendedMissingOutputsArrays)6263 TEST_P(WebGLCompatibilityTest, EXTBlendFuncExtendedMissingOutputsArrays)
6264 {
6265     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
6266 
6267     glEnable(GL_BLEND);
6268     glBlendFunc(GL_ONE, GL_SRC1_COLOR_EXT);
6269     ASSERT_GL_NO_ERROR();
6270 
6271     {
6272         constexpr char kFragData[] = R"(
6273 void main() {
6274     gl_FragData[0] = vec4(1.0, 0.0, 0.0, 1.0);
6275 })";
6276         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFragData);
6277         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6278         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6279     }
6280     {
6281         constexpr char kSecondaryFragData[] = R"(#extension GL_EXT_blend_func_extended : require
6282 void main() {
6283     gl_SecondaryFragDataEXT[0] = vec4(0.0, 1.0, 0.0, 1.0);
6284 })";
6285         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kSecondaryFragData);
6286         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6287         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6288     }
6289     {
6290         constexpr char kFragDataAndSecondaryFragData[] =
6291             R"(#extension GL_EXT_blend_func_extended : require
6292 void main() {
6293     gl_FragData[0]             = vec4(1.0, 0.0, 0.0, 1.0);
6294     gl_SecondaryFragDataEXT[0] = vec4(0.0, 1.0, 0.0, 1.0);
6295 })";
6296         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFragDataAndSecondaryFragData);
6297         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6298         ASSERT_GL_NO_ERROR();
6299     }
6300 }
6301 
6302 // Test that both fragment outputs must be statically used
6303 // when enabling SRC1 blend functions in WebGL 2.0 contexts.
TEST_P(WebGL2CompatibilityTest,EXTBlendFuncExtendedMissingOutputs)6304 TEST_P(WebGL2CompatibilityTest, EXTBlendFuncExtendedMissingOutputs)
6305 {
6306     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
6307 
6308     glEnable(GL_BLEND);
6309     glBlendFunc(GL_ONE, GL_SRC1_COLOR_EXT);
6310     ASSERT_GL_NO_ERROR();
6311 
6312     {
6313         constexpr char kColor0[] = R"(#version 300 es
6314 out mediump vec4 color0;
6315 void main() {
6316     color0 = vec4(1.0, 0.0, 0.0, 1.0);
6317 })";
6318         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kColor0);
6319         drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6320         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6321     }
6322     {
6323         constexpr char kColor1[] = R"(#version 300 es
6324 #extension GL_EXT_blend_func_extended : require
6325 layout(location = 0, index = 1) out mediump vec4 color1;
6326 void main() {
6327     color1 = vec4(0.0, 1.0, 0.0, 1.0);
6328 })";
6329         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kColor1);
6330         drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6331         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6332     }
6333     {
6334         constexpr char kColor0AndColor1[] = R"(#version 300 es
6335 #extension GL_EXT_blend_func_extended : require
6336 layout(location = 0, index = 0) out mediump vec4 color0;
6337 layout(location = 0, index = 1) out mediump vec4 color1;
6338 void main() {
6339     color0 = vec4(1.0, 0.0, 0.0, 1.0);
6340     color1 = vec4(0.0, 1.0, 0.0, 1.0);
6341 })";
6342         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kColor0AndColor1);
6343         drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6344         ASSERT_GL_NO_ERROR();
6345     }
6346 }
6347 
6348 // Test that both fragment outputs must be statically used
6349 // when enabling SRC1 blend functions in WebGL 2.0 contexts.
TEST_P(WebGL2CompatibilityTest,EXTBlendFuncExtendedMissingOutputsArrays)6350 TEST_P(WebGL2CompatibilityTest, EXTBlendFuncExtendedMissingOutputsArrays)
6351 {
6352     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
6353 
6354     glEnable(GL_BLEND);
6355     glBlendFunc(GL_ONE, GL_SRC1_COLOR_EXT);
6356     ASSERT_GL_NO_ERROR();
6357 
6358     {
6359         constexpr char kArrayColor0[] = R"(#version 300 es
6360 out mediump vec4 color0[1];
6361 void main() {
6362     color0[0] = vec4(1.0, 0.0, 0.0, 1.0);
6363 })";
6364         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kArrayColor0);
6365         drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6366         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6367     }
6368     {
6369         constexpr char kArrayColor1[] = R"(#version 300 es
6370 #extension GL_EXT_blend_func_extended : require
6371 layout(location = 0, index = 1) out mediump vec4 color1[1];
6372 void main() {
6373     color1[0] = vec4(0.0, 1.0, 0.0, 1.0);
6374 })";
6375         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kArrayColor1);
6376         drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6377         ASSERT_GL_ERROR(GL_INVALID_OPERATION);
6378     }
6379     {
6380         constexpr char kArrayColor0AndColor0[] = R"(#version 300 es
6381 #extension GL_EXT_blend_func_extended : require
6382 layout(location = 0, index = 0) out mediump vec4 color0[1];
6383 layout(location = 0, index = 1) out mediump vec4 color1[1];
6384 void main() {
6385     color0[0] = vec4(1.0, 0.0, 0.0, 1.0);
6386     color1[0] = vec4(0.0, 1.0, 0.0, 1.0);
6387 })";
6388         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kArrayColor0AndColor0);
6389         drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
6390         ASSERT_GL_NO_ERROR();
6391     }
6392 }
6393 
6394 // Test that vertex conversion correctly no-ops when the vertex format requires conversion but there
6395 // are no vertices to convert.
TEST_P(WebGLCompatibilityTest,ConversionWithNoVertices)6396 TEST_P(WebGLCompatibilityTest, ConversionWithNoVertices)
6397 {
6398     constexpr char kVS[] = R"(precision highp float;
6399 attribute vec3 attr1;
6400 void main(void) {
6401    gl_Position = vec4(attr1, 1.0);
6402 })";
6403 
6404     constexpr char kFS[] = R"(precision highp float;
6405 void main(void) {
6406    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
6407 })";
6408 
6409     GLBuffer buffer;
6410     glBindBuffer(GL_ARRAY_BUFFER, buffer);
6411     std::array<int8_t, 12> data = {
6412         1,
6413     };
6414     glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(data[0]), data.data(), GL_STATIC_DRAW);
6415 
6416     ANGLE_GL_PROGRAM(program, kVS, kFS);
6417     glBindAttribLocation(program, 0, "attr1");
6418     glLinkProgram(program);
6419     ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
6420     glUseProgram(program);
6421 
6422     // Set the offset of the attribute past the end of the buffer but use a format that requires
6423     // conversion in Vulkan
6424     glEnableVertexAttribArray(0);
6425     glVertexAttribPointer(0, 3, GL_BYTE, true, 128, reinterpret_cast<void *>(256));
6426 
6427     glDrawArrays(GL_TRIANGLES, 0, 3);
6428     // Either no error or invalid operation is okay.
6429 }
6430 
6431 // Tests that using an out of bounds draw offset with a dynamic array succeeds.
TEST_P(WebGLCompatibilityTest,DynamicVertexArrayOffsetOutOfBounds)6432 TEST_P(WebGLCompatibilityTest, DynamicVertexArrayOffsetOutOfBounds)
6433 {
6434     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
6435     glUseProgram(program);
6436 
6437     GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
6438     ASSERT_NE(-1, posLoc);
6439 
6440     glEnableVertexAttribArray(posLoc);
6441     GLBuffer buf;
6442     glBindBuffer(GL_ARRAY_BUFFER, buf);
6443     glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const void *>(500));
6444     glBufferData(GL_ARRAY_BUFFER, 100, nullptr, GL_DYNAMIC_DRAW);
6445     glDrawArrays(GL_TRIANGLES, 0, 3);
6446 
6447     // Either no error or invalid operation is okay.
6448 }
6449 
6450 // Covers situations where vertex conversion could read out of bounds.
TEST_P(WebGL2CompatibilityTest,OutOfBoundsByteAttribute)6451 TEST_P(WebGL2CompatibilityTest, OutOfBoundsByteAttribute)
6452 {
6453     ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
6454     glUseProgram(testProgram);
6455 
6456     GLBuffer buffer;
6457     glBindBuffer(GL_ARRAY_BUFFER, buffer);
6458     glBufferData(GL_ARRAY_BUFFER, 2, nullptr, GL_STREAM_COPY);
6459 
6460     glEnableVertexAttribArray(0);
6461     glVertexAttribPointer(0, 4, GL_BYTE, false, 0xff, reinterpret_cast<const void *>(0xfe));
6462 
6463     glDrawArraysInstanced(GL_TRIANGLE_STRIP, 1, 10, 1000);
6464 }
6465 
6466 // Test for a mishandling of instanced vertex attributes with zero-sized buffers bound on Apple
6467 // OpenGL drivers.
TEST_P(WebGL2CompatibilityTest,DrawWithZeroSizedBuffer)6468 TEST_P(WebGL2CompatibilityTest, DrawWithZeroSizedBuffer)
6469 {
6470     ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
6471     glUseProgram(program);
6472 
6473     GLBuffer buffer;
6474     glBindBuffer(GL_ARRAY_BUFFER, buffer);
6475 
6476     GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
6477     glEnableVertexAttribArray(posLocation);
6478 
6479     glVertexAttribDivisor(posLocation, 1);
6480     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 9,
6481                           reinterpret_cast<void *>(0x41424344));
6482     ASSERT_GL_NO_ERROR();
6483 
6484     glDrawArrays(GL_TRIANGLES, 0, 6);
6485     // This should be caught as an invalid draw
6486     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6487 }
6488 
6489 // Test that draw calls exceeding the vertex attribute range are caught in the presence of both
6490 // instanced and non-instanced attributes.
TEST_P(WebGL2CompatibilityTest,DrawWithInstancedAndNonInstancedAttributes)6491 TEST_P(WebGL2CompatibilityTest, DrawWithInstancedAndNonInstancedAttributes)
6492 {
6493     if (IsGLExtensionRequestable("GL_ANGLE_base_vertex_base_instance"))
6494     {
6495         glRequestExtensionANGLE("GL_ANGLE_base_vertex_base_instance");
6496     }
6497 
6498     const bool hasBaseInstance = IsGLExtensionEnabled("GL_ANGLE_base_vertex_base_instance");
6499 
6500     constexpr char kVS[] = R"(#version 300 es
6501 in vec4 attr1;
6502 in vec2 attr2;
6503 in vec4 attr3;
6504 in vec3 attr4;
6505 
6506 out vec4 v1;
6507 out vec2 v2;
6508 out vec4 v3;
6509 out vec3 v4;
6510 
6511 void main()
6512 {
6513     v1 = attr1;
6514     v2 = attr2;
6515     v3 = attr3;
6516     v4 = attr4;
6517     gl_Position = vec4(0, 0, 0, 0);
6518 })";
6519 
6520     constexpr char kFS[] = R"(#version 300 es
6521 precision mediump float;
6522 
6523 in vec4 v1;
6524 in vec2 v2;
6525 in vec4 v3;
6526 in vec3 v4;
6527 
6528 out vec4 color;
6529 
6530 void main()
6531 {
6532     color = v1 + v2.xyxy + v3 + v4.xyxz;
6533 })";
6534 
6535     ANGLE_GL_PROGRAM(program, kVS, kFS);
6536     glUseProgram(program);
6537 
6538     const GLint attrLocations[4] = {
6539         glGetAttribLocation(program, "attr1"),
6540         glGetAttribLocation(program, "attr2"),
6541         glGetAttribLocation(program, "attr3"),
6542         glGetAttribLocation(program, "attr4"),
6543     };
6544 
6545     GLBuffer buffers[4];
6546 
6547     // Set up all the buffers as such:
6548     //
6549     // Buffer 1: 64 bytes + (offset) 124
6550     // Buffer 2: 16 bytes + (offset) 212
6551     // Buffer 3: 128 bytes + (offset) 76
6552     // Buffer 4: 96 bytes + (offset) 52
6553     constexpr GLsizei kBufferSizes[4] = {
6554         64,
6555         16,
6556         128,
6557         96,
6558     };
6559     constexpr GLsizei kBufferOffsets[4] = {
6560         124,
6561         212,
6562         76,
6563         52,
6564     };
6565     // Attribute component count corresponding to the shader
6566     constexpr GLint kAttrComponents[4] = {
6567         4,
6568         2,
6569         4,
6570         3,
6571     };
6572     // Attribute types
6573     constexpr GLenum kAttrTypes[4] = {
6574         GL_SHORT,
6575         GL_BYTE,
6576         GL_FLOAT,
6577         GL_UNSIGNED_SHORT,
6578     };
6579     // Attribute strides.
6580     //
6581     // - Buffer 1 has 64 bytes, each attribute is 8 bytes.  With a stride of 12, 5 vertices can be
6582     //   drawn from this buffer.
6583     // - Buffer 2 has 16 bytes, each attribute is 2 bytes.  With a stride of 0, 8 vertices can be
6584     //   drawn from this buffer.
6585     // - Buffer 3 has 128 bytes, each attribute is 16 bytes.  With a stride of 20, 6 vertices can be
6586     //   drawn from this buffer.
6587     // - Buffer 4 has 96 bytes, each attribute is 6 bytes.  With a stride of 8, 12 vertices can be
6588     //   drawn from this buffer.
6589     constexpr GLsizei kAttrStrides[4] = {
6590         12,
6591         0,
6592         20,
6593         8,
6594     };
6595 
6596     for (int i = 0; i < 4; ++i)
6597     {
6598         glBindBuffer(GL_ARRAY_BUFFER, buffers[i]);
6599         glBufferData(GL_ARRAY_BUFFER, kBufferSizes[i] + kBufferOffsets[i], nullptr, GL_STATIC_DRAW);
6600 
6601         glEnableVertexAttribArray(attrLocations[i]);
6602         glVertexAttribPointer(attrLocations[i], kAttrComponents[i], kAttrTypes[i], GL_TRUE,
6603                               kAttrStrides[i], reinterpret_cast<void *>(kBufferOffsets[i]));
6604     }
6605     ASSERT_GL_NO_ERROR();
6606 
6607     // Without any attribute divisors, the maximum vertex attribute allowed is min(5, 8, 6, 12) with
6608     // non-instanced draws.
6609     glDrawArrays(GL_POINTS, 0, 4);
6610     EXPECT_GL_NO_ERROR();
6611     glDrawArrays(GL_POINTS, 0, 5);
6612     EXPECT_GL_NO_ERROR();
6613     glDrawArrays(GL_POINTS, 0, 6);
6614     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6615     glDrawArrays(GL_POINTS, 1, 5);
6616     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6617     glDrawArrays(GL_POINTS, 1, 4);
6618     EXPECT_GL_NO_ERROR();
6619     glDrawArrays(GL_POINTS, 4, 1);
6620     EXPECT_GL_NO_ERROR();
6621     glDrawArrays(GL_POINTS, 4, 2);
6622     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6623     glDrawArrays(GL_POINTS, 5, 1);
6624     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6625     glDrawArrays(GL_POINTS, 200, 1);
6626     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6627     // Same with instanced draws.
6628     glDrawArraysInstanced(GL_POINTS, 0, 4, 10);
6629     EXPECT_GL_NO_ERROR();
6630     glDrawArraysInstanced(GL_POINTS, 0, 5, 1);
6631     EXPECT_GL_NO_ERROR();
6632     glDrawArraysInstanced(GL_POINTS, 0, 6, 5);
6633     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6634     glDrawArraysInstanced(GL_POINTS, 1, 5, 1);
6635     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6636     glDrawArraysInstanced(GL_POINTS, 1, 4, 22);
6637     EXPECT_GL_NO_ERROR();
6638     glDrawArraysInstanced(GL_POINTS, 4, 1, 1240);
6639     EXPECT_GL_NO_ERROR();
6640     glDrawArraysInstanced(GL_POINTS, 4, 2, 1);
6641     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6642     glDrawArraysInstanced(GL_POINTS, 5, 1, 6);
6643     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6644     glDrawArraysInstanced(GL_POINTS, 200, 1, 100);
6645     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6646 
6647     // With a divisor on attribute 1, that attribute can reference up to vertex #5 (as first
6648     // attribute), while the rest are limited to min(8, 6, 12) as their maximum vertex attribute.
6649     glVertexAttribDivisor(attrLocations[0], 5);
6650 
6651     glDrawArrays(GL_POINTS, 0, 5);
6652     EXPECT_GL_NO_ERROR();
6653     glDrawArrays(GL_POINTS, 0, 6);
6654     EXPECT_GL_NO_ERROR();
6655     glDrawArrays(GL_POINTS, 0, 7);
6656     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6657     // The following passes because attribute 1 only accesses index 0 regardless of first
6658     glDrawArrays(GL_POINTS, 4, 2);
6659     EXPECT_GL_NO_ERROR();
6660     // The following fails because attribute 3 accesses vertices [4, 7)
6661     glDrawArrays(GL_POINTS, 4, 3);
6662     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6663     glDrawArrays(GL_POINTS, 5, 1);
6664     EXPECT_GL_NO_ERROR();
6665 
6666     // With instanced rendering, the same limits as above hold.  Additionally, attribute 1 does no
6667     // longer access only a single vertex, but it accesses instanceCount/5 (5 being the divisor)
6668     // elements.
6669     // The following passes because attribute 1 accesses vertices [0, 4)
6670     glDrawArraysInstanced(GL_POINTS, 0, 5, 20);
6671     EXPECT_GL_NO_ERROR();
6672     // The following passes because attribute 1 accesses vertices [0, 5)
6673     glDrawArraysInstanced(GL_POINTS, 0, 6, 25);
6674     EXPECT_GL_NO_ERROR();
6675     // The following fails because of the limit on non-instanced attributes
6676     glDrawArraysInstanced(GL_POINTS, 0, 7, 1);
6677     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6678     // The following fails because attribute 1 accesses vertices [0, 6)
6679     glDrawArraysInstanced(GL_POINTS, 0, 4, 26);
6680     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6681     // The following passes because attribute 1 accesses vertices [0, 2).  Recall that first vertex
6682     // is ignored for instanced attributes.
6683     glDrawArraysInstanced(GL_POINTS, 3, 3, 9);
6684     EXPECT_GL_NO_ERROR();
6685     glDrawArraysInstanced(GL_POINTS, 3, 3, 10);
6686     EXPECT_GL_NO_ERROR();
6687     glDrawArraysInstanced(GL_POINTS, 3, 3, 11);
6688     EXPECT_GL_NO_ERROR();
6689     glDrawArraysInstanced(GL_POINTS, 5, 1, 1);
6690     EXPECT_GL_NO_ERROR();
6691 
6692     if (hasBaseInstance)
6693     {
6694         // The following passes because attribute 1 accesses vertices [0, 3)
6695         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 15, 0);
6696         EXPECT_GL_NO_ERROR();
6697         // The following passes because attribute 1 accesses vertices [1, 4)
6698         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 15, 5);
6699         EXPECT_GL_NO_ERROR();
6700         // The following passes because attribute 1 accesses vertices [0, 4)
6701         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 17, 3);
6702         EXPECT_GL_NO_ERROR();
6703         // The following passes because attribute 1 accesses vertices [3, 5)
6704         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 10, 15);
6705         EXPECT_GL_NO_ERROR();
6706         // The following fails because attribute 1 accesses vertices [3, 6)
6707         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 11, 15);
6708         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6709         // The following fails because attribute 1 accesses vertex 6
6710         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 1, 25);
6711         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6712     }
6713 
6714     // With a divisor on attribute 3, that attribute can reference up to vertex #6 (as first
6715     // attribute), while the rest are limited to min(8, 12) as their maximum vertex attribute.
6716     glVertexAttribDivisor(attrLocations[2], 3);
6717 
6718     glDrawArrays(GL_POINTS, 0, 7);
6719     EXPECT_GL_NO_ERROR();
6720     glDrawArrays(GL_POINTS, 0, 8);
6721     EXPECT_GL_NO_ERROR();
6722     glDrawArrays(GL_POINTS, 0, 9);
6723     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6724     // The following passes because attribute 1 and 3 only access index 0 regardless of first and
6725     // count
6726     glDrawArrays(GL_POINTS, 4, 4);
6727     EXPECT_GL_NO_ERROR();
6728     // The following fails because attribute 2 accesses vertices [4, 9)
6729     glDrawArrays(GL_POINTS, 4, 5);
6730     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6731     glDrawArrays(GL_POINTS, 5, 1);
6732     EXPECT_GL_NO_ERROR();
6733     glDrawArrays(GL_POINTS, 6, 1);
6734     EXPECT_GL_NO_ERROR();
6735 
6736     // With instanced rendering, the same limits as above hold.  Additionally, attribute 1 accesses
6737     // instanceCount/5 and attribute 3 accesses instanceCount/3 elements.
6738     // The following passes because attribute 1 accesses vertices [0, 4), and attribute 3 accesses
6739     // vertices [0, 6)
6740     glDrawArraysInstanced(GL_POINTS, 0, 5, 18);
6741     EXPECT_GL_NO_ERROR();
6742     glDrawArraysInstanced(GL_POINTS, 0, 8, 18);
6743     EXPECT_GL_NO_ERROR();
6744     // The following fails because attribute 3 accesses vertices [0, 7)
6745     glDrawArraysInstanced(GL_POINTS, 0, 5, 19);
6746     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6747     // The following fails because of the limit on non-instanced attributes
6748     glDrawArraysInstanced(GL_POINTS, 0, 9, 1);
6749     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6750     // The following passes because attribute 1 accesses vertices [0, 3), and attribute 3 accesses
6751     // vertices [0, 4)
6752     glDrawArraysInstanced(GL_POINTS, 2, 4, 11);
6753     EXPECT_GL_NO_ERROR();
6754     glDrawArraysInstanced(GL_POINTS, 2, 4, 12);
6755     EXPECT_GL_NO_ERROR();
6756     // The following passes because attribute 3 accesses vertices [0, 5).  Attribute 1 still
6757     // accesses within limits of [0, 3)
6758     glDrawArraysInstanced(GL_POINTS, 2, 4, 13);
6759     EXPECT_GL_NO_ERROR();
6760     glDrawArraysInstanced(GL_POINTS, 5, 1, 1);
6761     EXPECT_GL_NO_ERROR();
6762 
6763     if (hasBaseInstance)
6764     {
6765         // The following passes because attribute 1 accesses vertices [0, 4), and attribute 3
6766         // accesses vertices [0, 6)
6767         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 18, 0);
6768         EXPECT_GL_NO_ERROR();
6769         // The following fails because attribute 3 accesses vertices [0, 7)
6770         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 19, 0);
6771         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6772         // The following fails because attribute 3 accesses vertices [1, 7)
6773         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 18, 1);
6774         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6775         // The following passes because attribute 3 accesses vertices [3, 6)
6776         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 7, 11);
6777         EXPECT_GL_NO_ERROR();
6778         // The following fails because attribute 3 accesses vertices [3, 7)
6779         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 2, 4, 8, 11);
6780         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6781     }
6782 
6783     // With a divisor on attribute 2, that attribute can reference up to vertex #8 (as first
6784     // attribute), and with a divisor on attribute 4, it can reference up to vertex #12.  There is
6785     // no particular limit on the maxmium vertex attribute when not instanced.
6786     glVertexAttribDivisor(attrLocations[1], 3);
6787     glVertexAttribDivisor(attrLocations[3], 1);
6788 
6789     // The following passes because all attributes only access index 0
6790     glDrawArrays(GL_POINTS, 0, 123);
6791     EXPECT_GL_NO_ERROR();
6792     glDrawArrays(GL_POINTS, 4, 500);
6793     EXPECT_GL_NO_ERROR();
6794     glDrawArrays(GL_POINTS, 5, 1);
6795     EXPECT_GL_NO_ERROR();
6796     glDrawArrays(GL_POINTS, 231, 1);
6797     EXPECT_GL_NO_ERROR();
6798 
6799     // With instanced rendering, the same limits as above hold.
6800     //
6801     // Attribute 1 accesses instanceCount/5 elements (note: buffer fits 5 vertices)
6802     // Attribute 2 accesses instanceCount/3 elements (note: buffer fits 8 vertices)
6803     // Attribute 3 accesses instanceCount/3 elements (note: buffer fits 6 vertices)
6804     // Attribute 4 accesses instanceCount/1 elements (note: buffer fits 12 vertices)
6805     //
6806     // Only instances [0, 12) are valid.
6807     glDrawArraysInstanced(GL_POINTS, 0, 123, 1);
6808     EXPECT_GL_NO_ERROR();
6809     // The following passes because attributes accessed are:
6810     // [0, 3), [0, 4), [0, 4), [0, 12)
6811     glDrawArraysInstanced(GL_POINTS, 0, 123, 12);
6812     EXPECT_GL_NO_ERROR();
6813     // The following fails because attributes accessed are:
6814     // [0, 3), [0, 5), [0, 5), [0, 13)
6815     //                              \-- overflow
6816     glDrawArraysInstanced(GL_POINTS, 0, 123, 13);
6817     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6818     // The following passes because attributes accessed are:
6819     // [0, 2), [0, 3), [0, 3), [0, 9)
6820     glDrawArraysInstanced(GL_POINTS, 3, 359, 9);
6821     EXPECT_GL_NO_ERROR();
6822     // The following fails because attributes accessed are:
6823     // [0, 3), [0, 5), [0, 5), [0, 13)
6824     //                              \-- overflow
6825     glDrawArraysInstanced(GL_POINTS, 3, 359, 13);
6826     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6827     // The following passes because attributes accessed are:
6828     // [0, 1), [0, 2), [0, 2), [0, 5)
6829     glDrawArraysInstanced(GL_POINTS, 120, 359, 5);
6830     EXPECT_GL_NO_ERROR();
6831 
6832     if (hasBaseInstance)
6833     {
6834         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 120, 359, 12, 0);
6835         EXPECT_GL_NO_ERROR();
6836         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 120, 359, 11, 1);
6837         EXPECT_GL_NO_ERROR();
6838         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 120, 359, 1, 11);
6839         EXPECT_GL_NO_ERROR();
6840         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 120, 359, 2, 11);
6841         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6842         glDrawArraysInstancedBaseInstanceANGLE(GL_POINTS, 120, 359, 1, 14);
6843         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
6844     }
6845 }
6846 
6847 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest);
6848 
6849 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2CompatibilityTest);
6850 ANGLE_INSTANTIATE_TEST_ES3(WebGL2CompatibilityTest);
6851 }  // namespace angle
6852