• 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.get());
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.get());
126         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
127 
128         GLFramebuffer fbo;
129         glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
130         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo.get());
131 
132         GLTexture texture;
133         glBindTexture(GL_TEXTURE_2D, texture.get());
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.get(), "tex"), 0);
167         glUniform4fv(glGetUniformLocation(samplingProgram.get(), "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.get(), "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.get(), "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.get(),
187                                0);
188         glBindTexture(GL_TEXTURE_2D, 0);
189         if (!renderingEnabled)
190         {
191             EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
192                              glCheckFramebufferStatus(GL_FRAMEBUFFER));
193             return;
194         }
195 
196         GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
197         if (framebufferStatus == GL_FRAMEBUFFER_UNSUPPORTED)
198         {
199             std::cout << "Framebuffer returned GL_FRAMEBUFFER_UNSUPPORTED, this is legal."
200                       << std::endl;
201             return;
202         }
203         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, framebufferStatus);
204 
205         ANGLE_GL_PROGRAM(renderingProgram, essl1_shaders::vs::Simple(),
206                          essl1_shaders::fs::UniformColor());
207         glUseProgram(renderingProgram.get());
208 
209         glUniform4fv(glGetUniformLocation(renderingProgram.get(), essl1_shaders::ColorUniform()), 1,
210                      floatData);
211 
212         drawQuad(renderingProgram.get(), essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
213 
214         EXPECT_PIXEL_COLOR32F_NEAR(
215             0, 0, GLColor32F(floatData[0], floatData[1], floatData[2], floatData[3]), 1.0f);
216     }
217 
TestExtFloatBlend(GLenum internalFormat,GLenum type,bool shouldBlend)218     void TestExtFloatBlend(GLenum internalFormat, GLenum type, bool shouldBlend)
219     {
220         constexpr char kVS[] =
221             R"(void main()
222 {
223     gl_PointSize = 1.0;
224     gl_Position = vec4(0, 0, 0, 1);
225 })";
226 
227         constexpr char kFS[] =
228             R"(void main()
229 {
230     gl_FragColor = vec4(0.5, 0, 0, 0);
231 })";
232 
233         ANGLE_GL_PROGRAM(program, kVS, kFS);
234         glUseProgram(program);
235 
236         GLTexture texture;
237         glBindTexture(GL_TEXTURE_2D, texture);
238         glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, GL_RGBA, type, nullptr);
239         EXPECT_GL_NO_ERROR();
240 
241         GLFramebuffer fbo;
242         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
243         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
244         ASSERT_EGLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
245 
246         glClearColor(1, 0, 1, 1);
247         glClear(GL_COLOR_BUFFER_BIT);
248         EXPECT_PIXEL_COLOR32F_NEAR(0, 0, GLColor32F(1, 0, 1, 1), 0.001f);
249 
250         glDisable(GL_BLEND);
251         glDrawArrays(GL_POINTS, 0, 1);
252         EXPECT_GL_NO_ERROR();
253 
254         glEnable(GL_BLEND);
255         glBlendFunc(GL_CONSTANT_COLOR, GL_ZERO);
256         glBlendColor(10, 1, 1, 1);
257         glViewport(0, 0, 1, 1);
258         glDrawArrays(GL_POINTS, 0, 1);
259         if (!shouldBlend)
260         {
261             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
262             return;
263         }
264         EXPECT_GL_NO_ERROR();
265 
266         if (!IsOpenGLES())
267         {
268             // GLES test machines will need a workaround.
269             EXPECT_PIXEL_COLOR32F_NEAR(0, 0, GLColor32F(5, 0, 0, 0), 0.001f);
270         }
271 
272         // Check sure that non-float attachments clamp BLEND_COLOR.
273         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
274         glDrawArrays(GL_POINTS, 0, 1);
275 
276         EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0x80, 0, 0, 0), 1);
277     }
278 
279     void TestDifferentStencilMaskAndRef(GLenum errIfMismatch);
280 
281     // Called from RenderingFeedbackLoopWithDrawBuffersEXT.
282     void drawBuffersEXTFeedbackLoop(GLuint program,
283                                     const std::array<GLenum, 2> &drawBuffers,
284                                     GLenum expectedError);
285 
286     // Called from RenderingFeedbackLoopWithDrawBuffers.
287     void drawBuffersFeedbackLoop(GLuint program,
288                                  const std::array<GLenum, 2> &drawBuffers,
289                                  GLenum expectedError);
290 
291     // Called from Enable[Compressed]TextureFormatExtensions
292     void validateTexImageExtensionFormat(GLenum format, const std::string &extName);
293     void validateCompressedTexImageExtensionFormat(GLenum format,
294                                                    GLsizei width,
295                                                    GLsizei height,
296                                                    GLsizei blockSize,
297                                                    const std::string &extName,
298                                                    bool subImageAllowed);
299 };
300 
301 class WebGL2CompatibilityTest : public WebGLCompatibilityTest
302 {};
303 
304 // Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
305 // the GL extension should always be present
TEST_P(WebGLCompatibilityTest,ExtensionStringExposed)306 TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
307 {
308     EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_webgl_compatibility"));
309 }
310 
311 // Verify that all extension entry points are available
TEST_P(WebGLCompatibilityTest,EntryPoints)312 TEST_P(WebGLCompatibilityTest, EntryPoints)
313 {
314     if (IsGLExtensionEnabled("GL_ANGLE_request_extension"))
315     {
316         EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
317     }
318 }
319 
320 // WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point.  Make sure it is usable,
321 // even in ES2 contexts.
TEST_P(WebGLCompatibilityTest,DepthStencilBindingPoint)322 TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
323 {
324     GLRenderbuffer renderbuffer;
325     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
326     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
327 
328     GLFramebuffer framebuffer;
329     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
330     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
331                               renderbuffer.get());
332 
333     EXPECT_GL_NO_ERROR();
334 }
335 
336 // Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
TEST_P(WebGLCompatibilityTest,EnableExtensionValidation)337 TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
338 {
339     glRequestExtensionANGLE("invalid_extension_string");
340     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
341 }
342 
343 // Test enabling the GL_OES_element_index_uint extension
TEST_P(WebGLCompatibilityTest,EnableExtensionUintIndices)344 TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
345 {
346     if (getClientMajorVersion() != 2)
347     {
348         // This test only works on ES2 where uint indices are not available by default
349         return;
350     }
351 
352     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_element_index_uint"));
353 
354     GLBuffer indexBuffer;
355     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
356 
357     GLuint data[] = {0, 1, 2, 1, 3, 2};
358     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
359 
360     ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
361                      "void main() { gl_FragColor = vec4(0, 1, 0, 1); }");
362     glUseProgram(program.get());
363 
364     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
365     EXPECT_GL_ERROR(GL_INVALID_ENUM);
366 
367     if (IsGLExtensionRequestable("GL_OES_element_index_uint"))
368     {
369         glRequestExtensionANGLE("GL_OES_element_index_uint");
370         EXPECT_GL_NO_ERROR();
371         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_element_index_uint"));
372 
373         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
374         EXPECT_GL_NO_ERROR();
375     }
376 }
377 
378 // Test enabling the GL_OES_standard_derivatives extension
TEST_P(WebGLCompatibilityTest,EnableExtensionStandardDerivitives)379 TEST_P(WebGLCompatibilityTest, EnableExtensionStandardDerivitives)
380 {
381     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_standard_derivatives"));
382 
383     constexpr char kFS[] =
384         R"(#extension GL_OES_standard_derivatives : require
385 void main() { gl_FragColor = vec4(dFdx(vec2(1.0, 1.0)).x, 1, 0, 1); })";
386     ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFS));
387 
388     if (IsGLExtensionRequestable("GL_OES_standard_derivatives"))
389     {
390         glRequestExtensionANGLE("GL_OES_standard_derivatives");
391         EXPECT_GL_NO_ERROR();
392         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_standard_derivatives"));
393 
394         GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
395         ASSERT_NE(0u, shader);
396         glDeleteShader(shader);
397     }
398 }
399 
400 // Test enabling the GL_EXT_shader_texture_lod extension
TEST_P(WebGLCompatibilityTest,EnableExtensionTextureLOD)401 TEST_P(WebGLCompatibilityTest, EnableExtensionTextureLOD)
402 {
403     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_shader_texture_lod"));
404 
405     constexpr char kFS[] =
406         R"(#extension GL_EXT_shader_texture_lod : require
407 uniform sampler2D u_texture;
408 void main() {
409     gl_FragColor = texture2DGradEXT(u_texture, vec2(0.0, 0.0), vec2(0.0, 0.0), vec2(0.0,
410 0.0));
411 })";
412     ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFS));
413 
414     if (IsGLExtensionRequestable("GL_EXT_shader_texture_lod"))
415     {
416         glRequestExtensionANGLE("GL_EXT_shader_texture_lod");
417         EXPECT_GL_NO_ERROR();
418         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_shader_texture_lod"));
419 
420         GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
421         ASSERT_NE(0u, shader);
422         glDeleteShader(shader);
423     }
424 }
425 
426 // Test enabling the GL_EXT_frag_depth extension
TEST_P(WebGLCompatibilityTest,EnableExtensionFragDepth)427 TEST_P(WebGLCompatibilityTest, EnableExtensionFragDepth)
428 {
429     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_frag_depth"));
430 
431     constexpr char kFS[] =
432         R"(#extension GL_EXT_frag_depth : require
433 void main() {
434     gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
435     gl_FragDepthEXT = 1.0;
436 })";
437     ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFS));
438 
439     if (IsGLExtensionRequestable("GL_EXT_frag_depth"))
440     {
441         glRequestExtensionANGLE("GL_EXT_frag_depth");
442         EXPECT_GL_NO_ERROR();
443         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_frag_depth"));
444 
445         GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
446         ASSERT_NE(0u, shader);
447         glDeleteShader(shader);
448     }
449 }
450 
451 // Test enabling the GL_EXT_texture_filter_anisotropic extension
TEST_P(WebGLCompatibilityTest,EnableExtensionTextureFilterAnisotropic)452 TEST_P(WebGLCompatibilityTest, EnableExtensionTextureFilterAnisotropic)
453 {
454     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_texture_filter_anisotropic"));
455 
456     GLfloat maxAnisotropy = 0.0f;
457     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
458     EXPECT_GL_ERROR(GL_INVALID_ENUM);
459 
460     GLTexture texture;
461     glBindTexture(GL_TEXTURE_2D, texture.get());
462     ASSERT_GL_NO_ERROR();
463 
464     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
465     EXPECT_GL_ERROR(GL_INVALID_ENUM);
466 
467     GLfloat currentAnisotropy = 0.0f;
468     glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
469     EXPECT_GL_ERROR(GL_INVALID_ENUM);
470 
471     if (IsGLExtensionRequestable("GL_EXT_texture_filter_anisotropic"))
472     {
473         glRequestExtensionANGLE("GL_EXT_texture_filter_anisotropic");
474         EXPECT_GL_NO_ERROR();
475         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_texture_filter_anisotropic"));
476 
477         glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
478         ASSERT_GL_NO_ERROR();
479         EXPECT_GE(maxAnisotropy, 2.0f);
480 
481         glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
482         ASSERT_GL_NO_ERROR();
483         EXPECT_EQ(1.0f, currentAnisotropy);
484 
485         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f);
486         ASSERT_GL_NO_ERROR();
487     }
488 }
489 
490 // Test enabling the EGL image extensions
TEST_P(WebGLCompatibilityTest,EnableExtensionEGLImage)491 TEST_P(WebGLCompatibilityTest, EnableExtensionEGLImage)
492 {
493     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_EGL_image"));
494     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_EGL_image_external"));
495     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_EGL_image_external_essl3"));
496     EXPECT_FALSE(IsGLExtensionEnabled("NV_EGL_stream_consumer_external"));
497 
498     constexpr char kFSES2[] =
499         R"(#extension GL_OES_EGL_image_external : require
500 precision highp float;
501 uniform samplerExternalOES sampler;
502 void main()
503 {
504     gl_FragColor = texture2D(sampler, vec2(0, 0));
505 })";
506     EXPECT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES2));
507 
508     constexpr char kFSES3[] =
509         R"(#version 300 es
510 #extension GL_OES_EGL_image_external_essl3 : require
511 precision highp float;
512 uniform samplerExternalOES sampler;
513 out vec4 my_FragColor;
514 void main()
515 {
516     my_FragColor = texture(sampler, vec2(0, 0));
517 })";
518     if (getClientMajorVersion() >= 3)
519     {
520         EXPECT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES3));
521     }
522 
523     glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
524     EXPECT_GL_ERROR(GL_INVALID_ENUM);
525 
526     GLint result;
527     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &result);
528     EXPECT_GL_ERROR(GL_INVALID_ENUM);
529 
530     if (IsGLExtensionRequestable("GL_OES_EGL_image_external"))
531     {
532         glRequestExtensionANGLE("GL_OES_EGL_image_external");
533         EXPECT_GL_NO_ERROR();
534         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external"));
535 
536         EXPECT_NE(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES2));
537 
538         glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
539         EXPECT_GL_NO_ERROR();
540 
541         glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &result);
542         EXPECT_GL_NO_ERROR();
543 
544         if (getClientMajorVersion() >= 3 &&
545             IsGLExtensionRequestable("GL_OES_EGL_image_external_essl3"))
546         {
547             glRequestExtensionANGLE("GL_OES_EGL_image_external_essl3");
548             EXPECT_GL_NO_ERROR();
549             EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external_essl3"));
550 
551             EXPECT_NE(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES3));
552         }
553         else
554         {
555             EXPECT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, kFSES3));
556         }
557     }
558 }
559 
560 // Verify that shaders are of a compatible spec when the extension is enabled.
TEST_P(WebGLCompatibilityTest,ExtensionCompilerSpec)561 TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
562 {
563     EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_webgl_compatibility"));
564 
565     // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
566     constexpr char kVS[] =
567         R"(struct Foo {
568     int _webgl_bar;
569 };
570 void main()
571 {
572     Foo foo = Foo(1);
573 })";
574 
575     // Default fragement shader.
576     constexpr char kFS[] =
577         R"(void main()
578 {
579     gl_FragColor = vec4(1.0,0.0,0.0,1.0);
580 })";
581 
582     GLuint program = CompileProgram(kVS, kFS);
583     EXPECT_EQ(0u, program);
584     glDeleteProgram(program);
585 }
586 
587 // Test enabling the GL_NV_pixel_buffer_object extension
TEST_P(WebGLCompatibilityTest,EnablePixelBufferObjectExtensions)588 TEST_P(WebGLCompatibilityTest, EnablePixelBufferObjectExtensions)
589 {
590     EXPECT_FALSE(IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
591     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_mapbuffer"));
592     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_map_buffer_range"));
593 
594     // These extensions become core in in ES3/WebGL2.
595     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
596 
597     // http://anglebug.com/5268
598     ANGLE_SKIP_TEST_IF(IsOSX() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
599 
600     GLBuffer buffer;
601     glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
602     EXPECT_GL_ERROR(GL_INVALID_ENUM);
603 
604     if (IsGLExtensionRequestable("GL_NV_pixel_buffer_object"))
605     {
606         glRequestExtensionANGLE("GL_NV_pixel_buffer_object");
607         EXPECT_GL_NO_ERROR();
608 
609         // Create a framebuffer to read from
610         GLRenderbuffer renderbuffer;
611         glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
612         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
613 
614         GLFramebuffer fbo;
615         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
616         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
617                                   renderbuffer);
618         EXPECT_GL_NO_ERROR();
619 
620         glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
621         EXPECT_GL_NO_ERROR();
622 
623         glBufferData(GL_PIXEL_PACK_BUFFER, 4, nullptr, GL_STATIC_DRAW);
624         glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
625         EXPECT_GL_NO_ERROR();
626     }
627 }
628 
629 // Test enabling the GL_EXT_texture_storage extension
TEST_P(WebGLCompatibilityTest,EnableTextureStorage)630 TEST_P(WebGLCompatibilityTest, EnableTextureStorage)
631 {
632     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_texture_storage"));
633 
634     GLTexture texture;
635     glBindTexture(GL_TEXTURE_2D, texture);
636 
637     GLint result;
638     glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &result);
639     if (getClientMajorVersion() >= 3)
640     {
641         EXPECT_GL_NO_ERROR();
642     }
643     else
644     {
645         EXPECT_GL_ERROR(GL_INVALID_ENUM);
646     }
647 
648     if (IsGLExtensionRequestable("GL_EXT_texture_storage"))
649     {
650         glRequestExtensionANGLE("GL_EXT_texture_storage");
651         EXPECT_GL_NO_ERROR();
652         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_texture_storage"));
653 
654         glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &result);
655         EXPECT_GL_NO_ERROR();
656 
657         const GLenum alwaysAcceptableFormats[] = {
658             GL_ALPHA8_EXT,
659             GL_LUMINANCE8_EXT,
660             GL_LUMINANCE8_ALPHA8_EXT,
661         };
662         for (const auto &acceptableFormat : alwaysAcceptableFormats)
663         {
664             GLTexture localTexture;
665             glBindTexture(GL_TEXTURE_2D, localTexture);
666             glTexStorage2DEXT(GL_TEXTURE_2D, 1, acceptableFormat, 1, 1);
667             EXPECT_GL_NO_ERROR();
668         }
669     }
670 }
671 
672 // Test enabling the GL_OES_mapbuffer and GL_EXT_map_buffer_range extensions
TEST_P(WebGLCompatibilityTest,EnableMapBufferExtensions)673 TEST_P(WebGLCompatibilityTest, EnableMapBufferExtensions)
674 {
675     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_mapbuffer"));
676     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_map_buffer_range"));
677 
678     // These extensions become core in in ES3/WebGL2.
679     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
680 
681     GLBuffer buffer;
682     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
683     glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4, nullptr, GL_STATIC_DRAW);
684 
685     glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
686     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
687 
688     glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
689     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
690 
691     GLint access = 0;
692     glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
693     EXPECT_GL_ERROR(GL_INVALID_ENUM);
694 
695     if (IsGLExtensionRequestable("GL_OES_mapbuffer"))
696     {
697         glRequestExtensionANGLE("GL_OES_mapbuffer");
698         EXPECT_GL_NO_ERROR();
699 
700         glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
701         glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
702         glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
703         EXPECT_GL_NO_ERROR();
704     }
705 
706     if (IsGLExtensionRequestable("GL_EXT_map_buffer_range"))
707     {
708         glRequestExtensionANGLE("GL_EXT_map_buffer_range");
709         EXPECT_GL_NO_ERROR();
710 
711         glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
712         glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
713         glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
714         EXPECT_GL_NO_ERROR();
715     }
716 }
717 
718 // Test enabling the GL_OES_fbo_render_mipmap extension
TEST_P(WebGLCompatibilityTest,EnableRenderMipmapExtension)719 TEST_P(WebGLCompatibilityTest, EnableRenderMipmapExtension)
720 {
721     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_fbo_render_mipmap"));
722 
723     // This extensions become core in in ES3/WebGL2.
724     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
725 
726     GLTexture texture;
727     glBindTexture(GL_TEXTURE_2D, texture);
728     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
729     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
730 
731     GLFramebuffer fbo;
732     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
733     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
734     EXPECT_GL_NO_ERROR();
735 
736     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
737     EXPECT_GL_ERROR(GL_INVALID_VALUE);
738 
739     if (IsGLExtensionRequestable("GL_OES_fbo_render_mipmap"))
740     {
741         glRequestExtensionANGLE("GL_OES_fbo_render_mipmap");
742         EXPECT_GL_NO_ERROR();
743 
744         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
745         EXPECT_GL_NO_ERROR();
746     }
747 }
748 
749 // Test enabling the GL_EXT_blend_minmax extension
TEST_P(WebGLCompatibilityTest,EnableBlendMinMaxExtension)750 TEST_P(WebGLCompatibilityTest, EnableBlendMinMaxExtension)
751 {
752     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_blend_minmax"));
753 
754     // This extensions become core in in ES3/WebGL2.
755     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
756 
757     glBlendEquation(GL_MIN);
758     EXPECT_GL_ERROR(GL_INVALID_ENUM);
759 
760     glBlendEquation(GL_MAX);
761     EXPECT_GL_ERROR(GL_INVALID_ENUM);
762 
763     if (IsGLExtensionRequestable("GL_EXT_blend_minmax"))
764     {
765         glRequestExtensionANGLE("GL_EXT_blend_minmax");
766         EXPECT_GL_NO_ERROR();
767 
768         glBlendEquation(GL_MIN);
769         glBlendEquation(GL_MAX);
770         EXPECT_GL_NO_ERROR();
771     }
772 }
773 
774 // Test enabling the query extensions
TEST_P(WebGLCompatibilityTest,EnableQueryExtensions)775 TEST_P(WebGLCompatibilityTest, EnableQueryExtensions)
776 {
777     // Seems to be causing a device lost. http://anglebug.com/2423
778     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
779 
780     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
781     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
782     EXPECT_FALSE(IsGLExtensionEnabled("GL_CHROMIUM_sync_query"));
783 
784     // This extensions become core in in ES3/WebGL2.
785     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
786 
787     GLQueryEXT badQuery;
788 
789     glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, badQuery);
790     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
791 
792     glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, badQuery);
793     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
794 
795     glBeginQueryEXT(GL_TIME_ELAPSED_EXT, badQuery);
796     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
797 
798     glQueryCounterEXT(GL_TIMESTAMP_EXT, badQuery);
799     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
800 
801     glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, badQuery);
802     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
803 
804     if (IsGLExtensionRequestable("GL_EXT_occlusion_query_boolean"))
805     {
806         glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
807         EXPECT_GL_NO_ERROR();
808 
809         GLQueryEXT query;
810         glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
811         glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
812         EXPECT_GL_NO_ERROR();
813     }
814 
815     if (IsGLExtensionRequestable("GL_EXT_disjoint_timer_query"))
816     {
817         glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
818         EXPECT_GL_NO_ERROR();
819 
820         GLQueryEXT query1;
821         glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query1);
822         glEndQueryEXT(GL_TIME_ELAPSED_EXT);
823         EXPECT_GL_NO_ERROR();
824 
825         GLQueryEXT query2;
826         glQueryCounterEXT(query2, GL_TIMESTAMP_EXT);
827         EXPECT_GL_NO_ERROR();
828     }
829 
830     if (IsGLExtensionRequestable("GL_CHROMIUM_sync_query"))
831     {
832         glRequestExtensionANGLE("GL_CHROMIUM_sync_query");
833         EXPECT_GL_NO_ERROR();
834 
835         GLQueryEXT query;
836         glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query);
837         glEndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
838         EXPECT_GL_NO_ERROR();
839     }
840 }
841 
842 // Test enabling the GL_ANGLE_framebuffer_multisample extension
TEST_P(WebGLCompatibilityTest,EnableFramebufferMultisampleExtension)843 TEST_P(WebGLCompatibilityTest, EnableFramebufferMultisampleExtension)
844 {
845     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_framebuffer_multisample"));
846 
847     // This extensions become core in in ES3/WebGL2.
848     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
849 
850     GLint maxSamples = 0;
851     glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
852     EXPECT_GL_ERROR(GL_INVALID_ENUM);
853 
854     GLRenderbuffer renderbuffer;
855     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
856     glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 1, GL_RGBA4, 1, 1);
857     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
858 
859     if (IsGLExtensionRequestable("GL_ANGLE_framebuffer_multisample"))
860     {
861         glRequestExtensionANGLE("GL_ANGLE_framebuffer_multisample");
862         EXPECT_GL_NO_ERROR();
863 
864         glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
865         EXPECT_GL_NO_ERROR();
866 
867         glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, maxSamples, GL_RGBA4, 1, 1);
868         EXPECT_GL_NO_ERROR();
869     }
870 }
871 
872 // Test enabling the GL_ANGLE_instanced_arrays extension
TEST_P(WebGLCompatibilityTest,EnableInstancedArraysExtensionANGLE)873 TEST_P(WebGLCompatibilityTest, EnableInstancedArraysExtensionANGLE)
874 {
875     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
876 
877     // This extensions become core in in ES3/WebGL2.
878     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
879 
880     GLint divisor = 0;
881     glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
882     EXPECT_GL_ERROR(GL_INVALID_ENUM);
883 
884     glVertexAttribDivisorANGLE(0, 1);
885     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
886 
887     if (IsGLExtensionRequestable("GL_ANGLE_instanced_arrays"))
888     {
889         glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
890         EXPECT_GL_NO_ERROR();
891 
892         glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
893         glVertexAttribDivisorANGLE(0, 1);
894         EXPECT_GL_NO_ERROR();
895     }
896 }
897 
898 // Test enabling the GL_EXT_instanced_arrays extension
TEST_P(WebGLCompatibilityTest,EnableInstancedArraysExtensionEXT)899 TEST_P(WebGLCompatibilityTest, EnableInstancedArraysExtensionEXT)
900 {
901     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_instanced_arrays"));
902 
903     // This extensions become core in in ES3/WebGL2.
904     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
905 
906     GLint divisor = 0;
907     glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
908     EXPECT_GL_ERROR(GL_INVALID_ENUM);
909 
910     glVertexAttribDivisorEXT(0, 1);
911     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
912 
913     if (IsGLExtensionRequestable("GL_EXT_instanced_arrays"))
914     {
915         glRequestExtensionANGLE("GL_EXT_instanced_arrays");
916         EXPECT_GL_NO_ERROR();
917 
918         glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
919         glVertexAttribDivisorEXT(0, 1);
920         EXPECT_GL_NO_ERROR();
921     }
922 }
923 
924 // Test enabling the GL_ANGLE_pack_reverse_row_order extension
TEST_P(WebGLCompatibilityTest,EnablePackReverseRowOrderExtension)925 TEST_P(WebGLCompatibilityTest, EnablePackReverseRowOrderExtension)
926 {
927     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_pack_reverse_row_order"));
928 
929     GLint result = 0;
930     glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
931     EXPECT_GL_ERROR(GL_INVALID_ENUM);
932 
933     glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
934     EXPECT_GL_ERROR(GL_INVALID_ENUM);
935 
936     if (IsGLExtensionRequestable("GL_ANGLE_pack_reverse_row_order"))
937     {
938         glRequestExtensionANGLE("GL_ANGLE_pack_reverse_row_order");
939         EXPECT_GL_NO_ERROR();
940 
941         glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
942         glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
943         EXPECT_GL_NO_ERROR();
944     }
945 }
946 
947 // Test enabling the GL_EXT_unpack_subimage extension
TEST_P(WebGLCompatibilityTest,EnablePackUnpackSubImageExtension)948 TEST_P(WebGLCompatibilityTest, EnablePackUnpackSubImageExtension)
949 {
950     EXPECT_FALSE(IsGLExtensionEnabled("GL_EXT_unpack_subimage"));
951 
952     // This extensions become core in in ES3/WebGL2.
953     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
954 
955     constexpr GLenum parameters[] = {
956         GL_UNPACK_ROW_LENGTH_EXT,
957         GL_UNPACK_SKIP_ROWS_EXT,
958         GL_UNPACK_SKIP_PIXELS_EXT,
959     };
960 
961     for (GLenum param : parameters)
962     {
963         GLint resultI = 0;
964         glGetIntegerv(param, &resultI);
965         EXPECT_GL_ERROR(GL_INVALID_ENUM);
966 
967         GLfloat resultF = 0.0f;
968         glGetFloatv(param, &resultF);
969         EXPECT_GL_ERROR(GL_INVALID_ENUM);
970 
971         glPixelStorei(param, 0);
972         EXPECT_GL_ERROR(GL_INVALID_ENUM);
973     }
974 
975     if (IsGLExtensionRequestable("GL_EXT_unpack_subimage"))
976     {
977         glRequestExtensionANGLE("GL_EXT_unpack_subimage");
978         EXPECT_GL_NO_ERROR();
979 
980         for (GLenum param : parameters)
981         {
982             GLint resultI = 0;
983             glGetIntegerv(param, &resultI);
984 
985             GLfloat resultF = 0.0f;
986             glGetFloatv(param, &resultF);
987 
988             glPixelStorei(param, 0);
989 
990             EXPECT_GL_NO_ERROR();
991         }
992     }
993 }
994 
TEST_P(WebGLCompatibilityTest,EnableTextureRectangle)995 TEST_P(WebGLCompatibilityTest, EnableTextureRectangle)
996 {
997     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
998 
999     GLTexture texture;
1000     glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
1001     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1002 
1003     GLint minFilter = 0;
1004     glGetTexParameteriv(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, &minFilter);
1005     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1006 
1007     if (IsGLExtensionRequestable("GL_ANGLE_texture_rectangle"))
1008     {
1009         glRequestExtensionANGLE("GL_ANGLE_texture_rectangle");
1010         EXPECT_GL_NO_ERROR();
1011 
1012         EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
1013 
1014         glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
1015         EXPECT_GL_NO_ERROR();
1016 
1017         glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1018                      nullptr);
1019         EXPECT_GL_NO_ERROR();
1020 
1021         glDisableExtensionANGLE("GL_ANGLE_texture_rectangle");
1022         EXPECT_GL_NO_ERROR();
1023 
1024         EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
1025 
1026         glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
1027         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1028     }
1029 }
1030 
1031 // Test enabling the GL_NV_pack_subimage extension
TEST_P(WebGLCompatibilityTest,EnablePackPackSubImageExtension)1032 TEST_P(WebGLCompatibilityTest, EnablePackPackSubImageExtension)
1033 {
1034     EXPECT_FALSE(IsGLExtensionEnabled("GL_NV_pack_subimage"));
1035 
1036     // This extensions become core in in ES3/WebGL2.
1037     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1038 
1039     constexpr GLenum parameters[] = {
1040         GL_PACK_ROW_LENGTH,
1041         GL_PACK_SKIP_ROWS,
1042         GL_PACK_SKIP_PIXELS,
1043     };
1044 
1045     for (GLenum param : parameters)
1046     {
1047         GLint resultI = 0;
1048         glGetIntegerv(param, &resultI);
1049         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1050 
1051         GLfloat resultF = 0.0f;
1052         glGetFloatv(param, &resultF);
1053         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1054 
1055         glPixelStorei(param, 0);
1056         EXPECT_GL_ERROR(GL_INVALID_ENUM);
1057     }
1058 
1059     if (IsGLExtensionRequestable("GL_NV_pack_subimage"))
1060     {
1061         glRequestExtensionANGLE("GL_NV_pack_subimage");
1062         EXPECT_GL_NO_ERROR();
1063 
1064         for (GLenum param : parameters)
1065         {
1066             GLint resultI = 0;
1067             glGetIntegerv(param, &resultI);
1068 
1069             GLfloat resultF = 0.0f;
1070             glGetFloatv(param, &resultF);
1071 
1072             glPixelStorei(param, 0);
1073 
1074             EXPECT_GL_NO_ERROR();
1075         }
1076     }
1077 }
1078 
TEST_P(WebGLCompatibilityTest,EnableRGB8RGBA8Extension)1079 TEST_P(WebGLCompatibilityTest, EnableRGB8RGBA8Extension)
1080 {
1081     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
1082 
1083     // This extensions become core in in ES3/WebGL2.
1084     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1085 
1086     GLRenderbuffer renderbuffer;
1087     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1088     EXPECT_GL_NO_ERROR();
1089 
1090     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 1, 1);
1091     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1092 
1093     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
1094     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1095 
1096     if (IsGLExtensionRequestable("GL_OES_rgb8_rgba8"))
1097     {
1098         glRequestExtensionANGLE("GL_OES_rgb8_rgba8");
1099         EXPECT_GL_NO_ERROR();
1100 
1101         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
1102 
1103         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 1, 1);
1104         EXPECT_GL_NO_ERROR();
1105 
1106         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
1107         EXPECT_GL_NO_ERROR();
1108     }
1109 }
1110 
1111 // Test enabling the GL_ANGLE_framebuffer_blit extension
TEST_P(WebGLCompatibilityTest,EnableFramebufferBlitExtension)1112 TEST_P(WebGLCompatibilityTest, EnableFramebufferBlitExtension)
1113 {
1114     EXPECT_FALSE(IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit"));
1115 
1116     // This extensions become core in in ES3/WebGL2.
1117     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1118 
1119     GLFramebuffer fbo;
1120 
1121     glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
1122     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1123 
1124     GLint result;
1125     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_ANGLE, &result);
1126     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1127 
1128     glBlitFramebufferANGLE(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1129     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1130 
1131     if (IsGLExtensionRequestable("GL_ANGLE_framebuffer_blit"))
1132     {
1133         glRequestExtensionANGLE("GL_ANGLE_framebuffer_blit");
1134         EXPECT_GL_NO_ERROR();
1135 
1136         glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
1137         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_ANGLE, &result);
1138         EXPECT_GL_NO_ERROR();
1139     }
1140 }
1141 
1142 // Test enabling the GL_OES_get_program_binary extension
TEST_P(WebGLCompatibilityTest,EnableProgramBinaryExtension)1143 TEST_P(WebGLCompatibilityTest, EnableProgramBinaryExtension)
1144 {
1145     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_get_program_binary"));
1146 
1147     // This extensions become core in in ES3/WebGL2.
1148     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1149 
1150     GLint result           = 0;
1151     GLint numBinaryFormats = 0;
1152     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinaryFormats);
1153     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1154 
1155     glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &result);
1156     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1157 
1158     constexpr char kVS[] =
1159         R"(void main()
1160 {
1161     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
1162 })";
1163     constexpr char kFS[] =
1164         R"(precision highp float;
1165 void main()
1166 {
1167     gl_FragColor = vec4(1.0);
1168 })";
1169     ANGLE_GL_PROGRAM(program, kVS, kFS);
1170 
1171     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &result);
1172     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1173 
1174     uint8_t tempArray[512];
1175     GLenum tempFormat  = 0;
1176     GLsizei tempLength = 0;
1177     glGetProgramBinaryOES(program, static_cast<GLsizei>(ArraySize(tempArray)), &tempLength,
1178                           &tempFormat, tempArray);
1179     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1180 
1181     if (IsGLExtensionRequestable("GL_OES_get_program_binary"))
1182     {
1183         glRequestExtensionANGLE("GL_OES_get_program_binary");
1184         EXPECT_GL_NO_ERROR();
1185 
1186         glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinaryFormats);
1187         // No use to test further if no binary formats are supported
1188         ANGLE_SKIP_TEST_IF(numBinaryFormats < 1);
1189 
1190         glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &result);
1191         EXPECT_GL_NO_ERROR();
1192 
1193         GLint binaryLength = 0;
1194         glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
1195         EXPECT_GL_NO_ERROR();
1196 
1197         GLenum binaryFormat;
1198         GLsizei writeLength = 0;
1199         std::vector<uint8_t> binary(binaryLength);
1200         glGetProgramBinaryOES(program, binaryLength, &writeLength, &binaryFormat, binary.data());
1201         EXPECT_GL_NO_ERROR();
1202 
1203         glProgramBinaryOES(program, binaryFormat, binary.data(), binaryLength);
1204         EXPECT_GL_NO_ERROR();
1205     }
1206 }
1207 
1208 // Test enabling the GL_OES_vertex_array_object extension
TEST_P(WebGLCompatibilityTest,EnableVertexArrayExtension)1209 TEST_P(WebGLCompatibilityTest, EnableVertexArrayExtension)
1210 {
1211     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_vertex_array_object"));
1212 
1213     // This extensions become core in in ES3/WebGL2.
1214     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1215 
1216     GLint result = 0;
1217     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &result);
1218     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1219 
1220     // Expect that GL_OES_vertex_array_object is always available.  It is implemented in the GL
1221     // frontend.
1222     EXPECT_TRUE(IsGLExtensionRequestable("GL_OES_vertex_array_object"));
1223 
1224     glRequestExtensionANGLE("GL_OES_vertex_array_object");
1225     EXPECT_GL_NO_ERROR();
1226 
1227     EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_vertex_array_object"));
1228 
1229     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &result);
1230     EXPECT_GL_NO_ERROR();
1231 
1232     GLuint vao = 0;
1233     glGenVertexArraysOES(0, &vao);
1234     EXPECT_GL_NO_ERROR();
1235 
1236     glBindVertexArrayOES(vao);
1237     EXPECT_GL_NO_ERROR();
1238 
1239     glDeleteVertexArraysOES(1, &vao);
1240     EXPECT_GL_NO_ERROR();
1241 }
1242 
1243 // Verify that the context generates the correct error when the framebuffer attachments are
1244 // different sizes
TEST_P(WebGLCompatibilityTest,FramebufferAttachmentSizeMismatch)1245 TEST_P(WebGLCompatibilityTest, FramebufferAttachmentSizeMismatch)
1246 {
1247     GLFramebuffer fbo;
1248     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1249 
1250     GLTexture textures[2];
1251     glBindTexture(GL_TEXTURE_2D, textures[0]);
1252     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1253     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
1254 
1255     ASSERT_GL_NO_ERROR();
1256     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1257 
1258     GLRenderbuffer renderbuffer;
1259     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1260     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 3, 3);
1261     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
1262 
1263     ASSERT_GL_NO_ERROR();
1264     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1265                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
1266 
1267     if (IsGLExtensionRequestable("GL_EXT_draw_buffers"))
1268     {
1269         glRequestExtensionANGLE("GL_EXT_draw_buffers");
1270         EXPECT_GL_NO_ERROR();
1271         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_draw_buffers"));
1272 
1273         glBindTexture(GL_TEXTURE_2D, textures[1]);
1274         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1275         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
1276         ASSERT_GL_NO_ERROR();
1277 
1278         ASSERT_GL_NO_ERROR();
1279         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1280                          glCheckFramebufferStatus(GL_FRAMEBUFFER));
1281 
1282         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
1283 
1284         ASSERT_GL_NO_ERROR();
1285         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1286 
1287         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1288 
1289         ASSERT_GL_NO_ERROR();
1290         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1291                          glCheckFramebufferStatus(GL_FRAMEBUFFER));
1292     }
1293 }
1294 
1295 // Test that client-side array buffers are forbidden in WebGL mode
TEST_P(WebGLCompatibilityTest,ForbidsClientSideArrayBuffer)1296 TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
1297 {
1298     constexpr char kVS[] =
1299         R"(attribute vec3 a_pos;
1300 void main()
1301 {
1302     gl_Position = vec4(a_pos, 1.0);
1303 })";
1304 
1305     constexpr char kFS[] =
1306         R"(precision highp float;
1307 void main()
1308 {
1309     gl_FragColor = vec4(1.0);
1310 })";
1311 
1312     ANGLE_GL_PROGRAM(program, kVS, kFS);
1313 
1314     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1315     ASSERT_NE(-1, posLocation);
1316     glUseProgram(program.get());
1317 
1318     const auto &vertices = GetQuadVertices();
1319     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
1320     glEnableVertexAttribArray(posLocation);
1321 
1322     ASSERT_GL_NO_ERROR();
1323     glDrawArrays(GL_TRIANGLES, 0, 6);
1324     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1325 }
1326 
1327 // Test that client-side element array buffers are forbidden in WebGL mode
TEST_P(WebGLCompatibilityTest,ForbidsClientSideElementBuffer)1328 TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
1329 {
1330     constexpr char kVS[] =
1331         R"(attribute vec3 a_pos;
1332 void main()
1333 {
1334     gl_Position = vec4(a_pos, 1.0);
1335 })";
1336 
1337     constexpr char kFS[] =
1338         R"(precision highp float;
1339 void main()
1340 {
1341     gl_FragColor = vec4(1.0);
1342 })";
1343 
1344     ANGLE_GL_PROGRAM(program, kVS, kFS);
1345 
1346     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1347     ASSERT_NE(-1, posLocation);
1348     glUseProgram(program.get());
1349 
1350     const auto &vertices = GetQuadVertices();
1351 
1352     GLBuffer vertexBuffer;
1353     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1354     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1355                  GL_STATIC_DRAW);
1356 
1357     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1358     glEnableVertexAttribArray(posLocation);
1359 
1360     ASSERT_GL_NO_ERROR();
1361 
1362     // Use the pointer with value of 1 for indices instead of an actual pointer because WebGL also
1363     // enforces that the top bit of indices must be 0 (i.e. offset >= 0) and would generate
1364     // GL_INVALID_VALUE in that case. Using a null pointer gets caught by another check.
1365     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(intptr_t(1)));
1366     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1367 }
1368 
1369 // Test that client-side array buffers are forbidden even if the program doesn't use the attribute
TEST_P(WebGLCompatibilityTest,ForbidsClientSideArrayBufferEvenNotUsedOnes)1370 TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBufferEvenNotUsedOnes)
1371 {
1372     constexpr char kVS[] =
1373         R"(void main()
1374 {
1375     gl_Position = vec4(1.0);
1376 })";
1377 
1378     constexpr char kFS[] =
1379         R"(precision highp float;
1380 void main()
1381 {
1382     gl_FragColor = vec4(1.0);
1383 })";
1384 
1385     ANGLE_GL_PROGRAM(program, kVS, kFS);
1386 
1387     glUseProgram(program.get());
1388 
1389     const auto &vertices = GetQuadVertices();
1390     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
1391     glEnableVertexAttribArray(0);
1392 
1393     ASSERT_GL_NO_ERROR();
1394     glDrawArrays(GL_TRIANGLES, 0, 6);
1395     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1396 }
1397 
1398 // Test that passing a null pixel data pointer to TexSubImage calls generates an INVALID_VALUE error
TEST_P(WebGLCompatibilityTest,NullPixelDataForSubImage)1399 TEST_P(WebGLCompatibilityTest, NullPixelDataForSubImage)
1400 {
1401     // glTexSubImage2D
1402     {
1403         GLTexture texture;
1404         glBindTexture(GL_TEXTURE_2D, texture);
1405 
1406         // TexImage with null data - OK
1407         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1408         EXPECT_GL_NO_ERROR();
1409 
1410         // TexSubImage with zero size and null data - OK
1411         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1412         EXPECT_GL_NO_ERROR();
1413 
1414         // TexSubImage with non-zero size and null data - Invalid value
1415         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1416         EXPECT_GL_ERROR(GL_INVALID_VALUE);
1417     }
1418 
1419     // glTexSubImage3D
1420     if (getClientMajorVersion() >= 3)
1421     {
1422         GLTexture texture;
1423         glBindTexture(GL_TEXTURE_3D, texture);
1424 
1425         // TexImage with null data - OK
1426         glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1427         EXPECT_GL_NO_ERROR();
1428 
1429         // TexSubImage with zero size and null data - OK
1430         glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1431         EXPECT_GL_NO_ERROR();
1432 
1433         // TexSubImage with non-zero size and null data - Invalid value
1434         glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1435         EXPECT_GL_ERROR(GL_INVALID_VALUE);
1436     }
1437 }
1438 
1439 // Tests the WebGL requirement of having the same stencil mask, writemask and ref for front and back
1440 // (when stencil testing is enabled)
TestDifferentStencilMaskAndRef(GLenum errIfMismatch)1441 void WebGLCompatibilityTest::TestDifferentStencilMaskAndRef(GLenum errIfMismatch)
1442 {
1443     // Run the test in an FBO to make sure we have some stencil bits.
1444     GLRenderbuffer renderbuffer;
1445     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
1446     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
1447 
1448     GLFramebuffer framebuffer;
1449     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1450     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1451                               renderbuffer.get());
1452 
1453     ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
1454                      "void main() { gl_FragColor = vec4(0, 1, 0, 1); }");
1455     glUseProgram(program.get());
1456     ASSERT_GL_NO_ERROR();
1457 
1458     // Having ref and mask the same for front and back is valid.
1459     glStencilMask(255);
1460     glStencilFunc(GL_ALWAYS, 0, 255);
1461     glDrawArrays(GL_TRIANGLES, 0, 6);
1462     ASSERT_GL_NO_ERROR();
1463 
1464     // Having a different front - back write mask generates an error.
1465     glStencilMaskSeparate(GL_FRONT, 1);
1466     glDrawArrays(GL_TRIANGLES, 0, 6);
1467     EXPECT_GL_ERROR(errIfMismatch);
1468 
1469     // Setting both write masks separately to the same value is valid.
1470     glStencilMaskSeparate(GL_BACK, 1);
1471     glDrawArrays(GL_TRIANGLES, 0, 6);
1472     ASSERT_GL_NO_ERROR();
1473 
1474     // Having a different stencil front - back mask generates an error
1475     glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
1476     glDrawArrays(GL_TRIANGLES, 0, 6);
1477     EXPECT_GL_ERROR(errIfMismatch);
1478 
1479     // Setting both masks separately to the same value is valid.
1480     glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
1481     glDrawArrays(GL_TRIANGLES, 0, 6);
1482     ASSERT_GL_NO_ERROR();
1483 
1484     // Having a different stencil front - back reference generates an error
1485     glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
1486     glDrawArrays(GL_TRIANGLES, 0, 6);
1487     EXPECT_GL_ERROR(errIfMismatch);
1488 
1489     // Setting both references separately to the same value is valid.
1490     glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
1491     glDrawArrays(GL_TRIANGLES, 0, 6);
1492     ASSERT_GL_NO_ERROR();
1493 
1494     // Using different stencil funcs, everything being equal is valid.
1495     glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
1496     glDrawArrays(GL_TRIANGLES, 0, 6);
1497     ASSERT_GL_NO_ERROR();
1498 }
1499 
TEST_P(WebGLCompatibilityTest,StencilTestEnabledDisallowsDifferentStencilMaskAndRef)1500 TEST_P(WebGLCompatibilityTest, StencilTestEnabledDisallowsDifferentStencilMaskAndRef)
1501 {
1502     glEnable(GL_STENCIL_TEST);
1503     TestDifferentStencilMaskAndRef(GL_INVALID_OPERATION);
1504 }
1505 
TEST_P(WebGLCompatibilityTest,StencilTestDisabledAllowsDifferentStencilMaskAndRef)1506 TEST_P(WebGLCompatibilityTest, StencilTestDisabledAllowsDifferentStencilMaskAndRef)
1507 {
1508     glDisable(GL_STENCIL_TEST);
1509     TestDifferentStencilMaskAndRef(GL_NO_ERROR);
1510 }
1511 
1512 // Test that GL_FIXED is forbidden
TEST_P(WebGLCompatibilityTest,ForbidsGLFixed)1513 TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
1514 {
1515     GLBuffer buffer;
1516     glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1517     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1518 
1519     glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1520     ASSERT_GL_NO_ERROR();
1521 
1522     glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
1523     EXPECT_GL_ERROR(GL_INVALID_ENUM);
1524 }
1525 
1526 // Test the WebGL limit of 255 for the attribute stride
TEST_P(WebGLCompatibilityTest,MaxStride)1527 TEST_P(WebGLCompatibilityTest, MaxStride)
1528 {
1529     GLBuffer buffer;
1530     glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1531     glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
1532 
1533     glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
1534     ASSERT_GL_NO_ERROR();
1535 
1536     glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
1537     EXPECT_GL_ERROR(GL_INVALID_VALUE);
1538 }
1539 
1540 // Test the checks for OOB reads in the vertex buffers, non-instanced version
TEST_P(WebGLCompatibilityTest,DrawArraysBufferOutOfBoundsNonInstanced)1541 TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
1542 {
1543     constexpr char kVS[] =
1544         R"(attribute float a_pos;
1545 void main()
1546 {
1547     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1548 })";
1549 
1550     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1551     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1552     ASSERT_NE(-1, posLocation);
1553     glUseProgram(program.get());
1554 
1555     GLBuffer buffer;
1556     glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1557     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1558 
1559     glEnableVertexAttribArray(posLocation);
1560 
1561     const uint8_t *zeroOffset = nullptr;
1562 
1563     // Test touching the last element is valid.
1564     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1565     glDrawArrays(GL_POINTS, 0, 4);
1566     ASSERT_GL_NO_ERROR();
1567 
1568     // Test touching the last element + 1 is invalid.
1569     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1570     glDrawArrays(GL_POINTS, 0, 4);
1571     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1572 
1573     // Test touching the last element is valid, using a stride.
1574     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1575     glDrawArrays(GL_POINTS, 0, 4);
1576     ASSERT_GL_NO_ERROR();
1577 
1578     // Test touching the last element + 1 is invalid, using a stride.
1579     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1580     glDrawArrays(GL_POINTS, 0, 4);
1581     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1582 
1583     // Test any offset is valid if no vertices are drawn.
1584     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1585     glDrawArrays(GL_POINTS, 0, 0);
1586     ASSERT_GL_NO_ERROR();
1587 
1588     // Test a case of overflow that could give a max vertex that's negative
1589     constexpr GLint kIntMax = std::numeric_limits<GLint>::max();
1590     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 0);
1591     glDrawArrays(GL_POINTS, kIntMax, kIntMax);
1592     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1593 }
1594 
1595 // Test that index values outside of the 32-bit integer range do not read out of bounds
TEST_P(WebGLCompatibilityTest,LargeIndexRange)1596 TEST_P(WebGLCompatibilityTest, LargeIndexRange)
1597 {
1598     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_element_index_uint"));
1599 
1600     constexpr char kVS[] =
1601         R"(attribute vec4 a_Position;
1602 void main()
1603 {
1604     gl_Position = a_Position;
1605 })";
1606 
1607     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1608     glUseProgram(program.get());
1609 
1610     glEnableVertexAttribArray(glGetAttribLocation(program, "a_Position"));
1611 
1612     constexpr float kVertexData[] = {
1613         1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1614     };
1615 
1616     GLBuffer vertexBuffer;
1617     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1618     glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STREAM_DRAW);
1619 
1620     constexpr GLuint kMaxIntAsGLuint = static_cast<GLuint>(std::numeric_limits<GLint>::max());
1621     constexpr GLuint kIndexData[]    = {
1622         kMaxIntAsGLuint,
1623         kMaxIntAsGLuint + 1,
1624         kMaxIntAsGLuint + 2,
1625         kMaxIntAsGLuint + 3,
1626     };
1627 
1628     GLBuffer indexBuffer;
1629     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBuffer);
1630     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexData), kIndexData, GL_DYNAMIC_DRAW);
1631 
1632     EXPECT_GL_NO_ERROR();
1633 
1634     // First index is representable as 32-bit int but second is not
1635     glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, 0);
1636     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1637 
1638     // Neither index is representable as 32-bit int
1639     glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, reinterpret_cast<void *>(sizeof(GLuint) * 2));
1640     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1641 }
1642 
1643 // Test for drawing with a null index buffer
TEST_P(WebGLCompatibilityTest,NullIndexBuffer)1644 TEST_P(WebGLCompatibilityTest, NullIndexBuffer)
1645 {
1646     constexpr char kVS[] =
1647         R"(attribute float a_pos;
1648 void main()
1649 {
1650     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1651 })";
1652 
1653     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1654     glUseProgram(program.get());
1655 
1656     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1657     glEnableVertexAttribArray(0);
1658 
1659     glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_BYTE, 0);
1660     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1661 }
1662 
1663 // Test the checks for OOB reads in the vertex buffers, instanced version
TEST_P(WebGL2CompatibilityTest,DrawArraysBufferOutOfBoundsInstanced)1664 TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
1665 {
1666     constexpr char kVS[] =
1667         R"(attribute float a_pos;
1668 attribute float a_w;
1669 void main()
1670 {
1671     gl_Position = vec4(a_pos, a_pos, a_pos, a_w);
1672 })";
1673 
1674     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1675     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1676     GLint wLocation   = glGetAttribLocation(program.get(), "a_w");
1677     ASSERT_NE(-1, posLocation);
1678     ASSERT_NE(-1, wLocation);
1679     glUseProgram(program.get());
1680 
1681     GLBuffer buffer;
1682     glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1683     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1684 
1685     glEnableVertexAttribArray(posLocation);
1686     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1687     glVertexAttribDivisor(posLocation, 0);
1688 
1689     glEnableVertexAttribArray(wLocation);
1690     glVertexAttribDivisor(wLocation, 1);
1691 
1692     const uint8_t *zeroOffset = nullptr;
1693 
1694     // Test touching the last element is valid.
1695     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1696     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1697     ASSERT_GL_NO_ERROR();
1698 
1699     // Test touching the last element + 1 is invalid.
1700     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1701     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1702     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1703 
1704     // Test touching the last element is valid, using a stride.
1705     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1706     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1707     ASSERT_GL_NO_ERROR();
1708 
1709     // Test touching the last element + 1 is invalid, using a stride.
1710     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1711     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1712     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1713 
1714     // Test any offset is valid if no vertices are drawn.
1715     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1716     glDrawArraysInstanced(GL_POINTS, 0, 0, 1);
1717     ASSERT_GL_NO_ERROR();
1718 
1719     // Test any offset is valid if no primitives are drawn.
1720     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1721     glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
1722     ASSERT_GL_NO_ERROR();
1723 }
1724 
1725 // Test the checks for OOB reads in the vertex buffers, ANGLE_instanced_arrays version
TEST_P(WebGLCompatibilityTest,DrawArraysBufferOutOfBoundsInstancedANGLE)1726 TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsInstancedANGLE)
1727 {
1728     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_ANGLE_instanced_arrays"));
1729     glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
1730     EXPECT_GL_NO_ERROR();
1731 
1732     constexpr char kVS[] =
1733         R"(attribute float a_pos;
1734 attribute float a_w;
1735 void main()
1736 {
1737     gl_Position = vec4(a_pos, a_pos, a_pos, a_w);
1738 })";
1739 
1740     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1741     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1742     GLint wLocation   = glGetAttribLocation(program.get(), "a_w");
1743     ASSERT_NE(-1, posLocation);
1744     ASSERT_NE(-1, wLocation);
1745     glUseProgram(program.get());
1746 
1747     GLBuffer buffer;
1748     glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1749     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1750 
1751     glEnableVertexAttribArray(posLocation);
1752     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1753     glVertexAttribDivisorANGLE(posLocation, 0);
1754 
1755     glEnableVertexAttribArray(wLocation);
1756     glVertexAttribDivisorANGLE(wLocation, 1);
1757 
1758     const uint8_t *zeroOffset = nullptr;
1759 
1760     // Test touching the last element is valid.
1761     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1762     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1763     ASSERT_GL_NO_ERROR() << "touching the last element.";
1764 
1765     // Test touching the last element + 1 is invalid.
1766     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1767     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1768     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "touching the last element + 1.";
1769 
1770     // Test touching the last element is valid, using a stride.
1771     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1772     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1773     ASSERT_GL_NO_ERROR() << "touching the last element using a stride.";
1774 
1775     // Test touching the last element + 1 is invalid, using a stride.
1776     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1777     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1778     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "touching the last element + 1 using a stride.";
1779 
1780     // Test any offset is valid if no vertices are drawn.
1781     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1782     glDrawArraysInstancedANGLE(GL_POINTS, 0, 0, 1);
1783     ASSERT_GL_NO_ERROR() << "any offset with no vertices.";
1784 
1785     // Test any offset is valid if no primitives are drawn.
1786     glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1787     glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 0);
1788     ASSERT_GL_NO_ERROR() << "any offset with primitives.";
1789 }
1790 
1791 // Test the checks for OOB reads in the index buffer
TEST_P(WebGLCompatibilityTest,DrawElementsBufferOutOfBoundsInIndexBuffer)1792 TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
1793 {
1794     constexpr char kVS[] =
1795         R"(attribute float a_pos;
1796 void main()
1797 {
1798     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1799 })";
1800 
1801     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1802     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1803     ASSERT_NE(-1, posLocation);
1804     glUseProgram(program.get());
1805 
1806     GLBuffer vertexBuffer;
1807     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1808     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1809 
1810     glEnableVertexAttribArray(posLocation);
1811     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1812 
1813     const uint8_t *zeroOffset   = nullptr;
1814     const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
1815 
1816     GLBuffer indexBuffer;
1817     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1818     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
1819     ASSERT_GL_NO_ERROR();
1820 
1821     // Test touching the last index is valid
1822     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
1823     ASSERT_GL_NO_ERROR();
1824 
1825     // Test touching the last + 1 element is invalid
1826     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
1827     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1828 
1829     // Test any offset if valid if count is zero
1830     glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
1831     ASSERT_GL_NO_ERROR();
1832 
1833     // Test touching the first index is valid
1834     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
1835     ASSERT_GL_NO_ERROR();
1836 
1837     // Test touching the first - 1 index is invalid
1838     // The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
1839     // the historic behavior of WebGL implementations
1840     glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset - 1);
1841     EXPECT_GL_ERROR(GL_INVALID_VALUE);
1842 }
1843 
1844 // Test the checks for OOB in vertex buffers caused by indices, non-instanced version
TEST_P(WebGLCompatibilityTest,DrawElementsBufferOutOfBoundsInVertexBuffer)1845 TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInVertexBuffer)
1846 {
1847     constexpr char kVS[] =
1848         R"(attribute float a_pos;
1849 void main()
1850 {
1851     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
1852 })";
1853 
1854     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
1855     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1856     ASSERT_NE(-1, posLocation);
1857     glUseProgram(program.get());
1858 
1859     GLBuffer vertexBuffer;
1860     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1861     glBufferData(GL_ARRAY_BUFFER, 8, nullptr, GL_STATIC_DRAW);
1862 
1863     glEnableVertexAttribArray(posLocation);
1864     glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1865 
1866     const uint8_t *zeroOffset   = nullptr;
1867     const uint8_t testIndices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 255};
1868 
1869     GLBuffer indexBuffer;
1870     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1871     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(testIndices), testIndices, GL_STATIC_DRAW);
1872     ASSERT_GL_NO_ERROR();
1873 
1874     // Test touching the end of the vertex buffer is valid
1875     glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 7);
1876     ASSERT_GL_NO_ERROR();
1877 
1878     // Test touching just after the end of the vertex buffer is invalid
1879     glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 8);
1880     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1881 
1882     // Test touching the whole vertex buffer is valid
1883     glDrawElements(GL_POINTS, 8, GL_UNSIGNED_BYTE, zeroOffset + 0);
1884     ASSERT_GL_NO_ERROR();
1885 
1886     // Test an index that would be negative
1887     glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 9);
1888     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1889 }
1890 
1891 // Test depth range with 'near' more or less than 'far.'
TEST_P(WebGLCompatibilityTest,DepthRange)1892 TEST_P(WebGLCompatibilityTest, DepthRange)
1893 {
1894     glDepthRangef(0, 1);
1895     ASSERT_GL_NO_ERROR();
1896 
1897     glDepthRangef(.5, .5);
1898     ASSERT_GL_NO_ERROR();
1899 
1900     glDepthRangef(1, 0);
1901     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1902 }
1903 
1904 // Test all blend function combinations.
1905 // In WebGL it is invalid to combine constant color with constant alpha.
TEST_P(WebGLCompatibilityTest,BlendWithConstantColor)1906 TEST_P(WebGLCompatibilityTest, BlendWithConstantColor)
1907 {
1908     constexpr GLenum srcFunc[] = {
1909         GL_ZERO,
1910         GL_ONE,
1911         GL_SRC_COLOR,
1912         GL_ONE_MINUS_SRC_COLOR,
1913         GL_DST_COLOR,
1914         GL_ONE_MINUS_DST_COLOR,
1915         GL_SRC_ALPHA,
1916         GL_ONE_MINUS_SRC_ALPHA,
1917         GL_DST_ALPHA,
1918         GL_ONE_MINUS_DST_ALPHA,
1919         GL_CONSTANT_COLOR,
1920         GL_ONE_MINUS_CONSTANT_COLOR,
1921         GL_CONSTANT_ALPHA,
1922         GL_ONE_MINUS_CONSTANT_ALPHA,
1923         GL_SRC_ALPHA_SATURATE,
1924     };
1925 
1926     constexpr GLenum dstFunc[] = {
1927         GL_ZERO,           GL_ONE,
1928         GL_SRC_COLOR,      GL_ONE_MINUS_SRC_COLOR,
1929         GL_DST_COLOR,      GL_ONE_MINUS_DST_COLOR,
1930         GL_SRC_ALPHA,      GL_ONE_MINUS_SRC_ALPHA,
1931         GL_DST_ALPHA,      GL_ONE_MINUS_DST_ALPHA,
1932         GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
1933         GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA,
1934     };
1935 
1936     for (GLenum src : srcFunc)
1937     {
1938         for (GLenum dst : dstFunc)
1939         {
1940             glBlendFunc(src, dst);
1941             CheckBlendFunctions(src, dst);
1942             glBlendFuncSeparate(src, dst, GL_ONE, GL_ONE);
1943             CheckBlendFunctions(src, dst);
1944         }
1945     }
1946 
1947     // Ensure the same semantics for indexed blendFunc
1948     if (IsGLExtensionRequestable("GL_OES_draw_buffers_indexed"))
1949     {
1950         glRequestExtensionANGLE("GL_OES_draw_buffers_indexed");
1951         EXPECT_GL_NO_ERROR();
1952         EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
1953 
1954         for (GLenum src : srcFunc)
1955         {
1956             for (GLenum dst : dstFunc)
1957             {
1958                 glBlendFunciOES(0, src, dst);
1959                 CheckBlendFunctions(src, dst);
1960                 glBlendFuncSeparateiOES(0, src, dst, GL_ONE, GL_ONE);
1961                 CheckBlendFunctions(src, dst);
1962             }
1963         }
1964     }
1965 }
1966 
1967 // Test draw state validation and invalidation wrt indexed blendFunc.
TEST_P(WebGLCompatibilityTest,IndexedBlendWithConstantColorInvalidation)1968 TEST_P(WebGLCompatibilityTest, IndexedBlendWithConstantColorInvalidation)
1969 {
1970     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
1971     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_OES_draw_buffers_indexed"));
1972 
1973     glRequestExtensionANGLE("GL_OES_draw_buffers_indexed");
1974     EXPECT_GL_NO_ERROR();
1975     EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
1976 
1977     constexpr char kVS[] =
1978         R"(#version 300 es
1979 void main()
1980 {
1981     gl_PointSize = 1.0;
1982     gl_Position = vec4(0, 0, 0, 1);
1983 })";
1984 
1985     constexpr char kFS[] =
1986         R"(#version 300 es
1987 precision lowp float;
1988 layout(location = 0) out vec4 o_color0;
1989 layout(location = 1) out vec4 o_color1;
1990 void main()
1991 {
1992     o_color0 = vec4(1, 0, 0, 1);
1993     o_color1 = vec4(0, 1, 0, 1);
1994 })";
1995 
1996     ANGLE_GL_PROGRAM(program, kVS, kFS);
1997     glUseProgram(program);
1998 
1999     glDisable(GL_BLEND);
2000     glEnableiOES(GL_BLEND, 0);
2001     glEnableiOES(GL_BLEND, 1);
2002 
2003     GLTexture texture1;
2004     glBindTexture(GL_TEXTURE_2D, texture1);
2005     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2006     EXPECT_GL_NO_ERROR();
2007 
2008     GLTexture texture2;
2009     glBindTexture(GL_TEXTURE_2D, texture2);
2010     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2011     EXPECT_GL_NO_ERROR();
2012 
2013     GLFramebuffer fbo;
2014     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2015     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
2016     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
2017     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2018 
2019     GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
2020     glDrawBuffers(2, drawbuffers);
2021 
2022     glDrawArrays(GL_POINTS, 0, 1);
2023     EXPECT_GL_NO_ERROR();
2024 
2025     // Force-invalidate draw call
2026     glBlendFuncSeparateiOES(0, GL_CONSTANT_COLOR, GL_CONSTANT_COLOR, GL_CONSTANT_ALPHA,
2027                             GL_CONSTANT_ALPHA);
2028     EXPECT_GL_NO_ERROR();
2029 
2030     glBlendFuncSeparateiOES(1, GL_CONSTANT_ALPHA, GL_CONSTANT_ALPHA, GL_CONSTANT_COLOR,
2031                             GL_CONSTANT_COLOR);
2032     EXPECT_GL_NO_ERROR();
2033 
2034     glDrawArrays(GL_POINTS, 0, 1);
2035     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2036 }
2037 
2038 // Test getIndexedParameter wrt GL_OES_draw_buffers_indexed.
TEST_P(WebGLCompatibilityTest,DrawBuffersIndexedGetIndexedParameter)2039 TEST_P(WebGLCompatibilityTest, DrawBuffersIndexedGetIndexedParameter)
2040 {
2041     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
2042     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_OES_draw_buffers_indexed"));
2043 
2044     GLint value;
2045     GLboolean data[4];
2046 
2047     glGetIntegeri_v(GL_BLEND_EQUATION_RGB, 0, &value);
2048     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2049     glGetIntegeri_v(GL_BLEND_EQUATION_ALPHA, 0, &value);
2050     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2051     glGetIntegeri_v(GL_BLEND_SRC_RGB, 0, &value);
2052     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2053     glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 0, &value);
2054     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2055     glGetIntegeri_v(GL_BLEND_DST_RGB, 0, &value);
2056     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2057     glGetIntegeri_v(GL_BLEND_DST_ALPHA, 0, &value);
2058     EXPECT_GL_ERROR(GL_INVALID_ENUM);
2059     glGetBooleani_v(GL_COLOR_WRITEMASK, 0, data);
2060     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2061 
2062     glRequestExtensionANGLE("GL_OES_draw_buffers_indexed");
2063     EXPECT_GL_NO_ERROR();
2064     EXPECT_TRUE(IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
2065 
2066     glDisable(GL_BLEND);
2067     glEnableiOES(GL_BLEND, 0);
2068     glBlendEquationSeparateiOES(0, GL_FUNC_ADD, GL_FUNC_SUBTRACT);
2069     glBlendFuncSeparateiOES(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ZERO);
2070     glColorMaskiOES(0, true, false, true, false);
2071     EXPECT_GL_NO_ERROR();
2072 
2073     EXPECT_EQ(true, glIsEnablediOES(GL_BLEND, 0));
2074     EXPECT_GL_NO_ERROR();
2075     glGetIntegeri_v(GL_BLEND_EQUATION_RGB, 0, &value);
2076     EXPECT_GL_NO_ERROR();
2077     EXPECT_EQ(GL_FUNC_ADD, value);
2078     glGetIntegeri_v(GL_BLEND_EQUATION_ALPHA, 0, &value);
2079     EXPECT_GL_NO_ERROR();
2080     EXPECT_EQ(GL_FUNC_SUBTRACT, value);
2081     glGetIntegeri_v(GL_BLEND_SRC_RGB, 0, &value);
2082     EXPECT_GL_NO_ERROR();
2083     EXPECT_EQ(GL_SRC_ALPHA, value);
2084     glGetIntegeri_v(GL_BLEND_SRC_ALPHA, 0, &value);
2085     EXPECT_GL_NO_ERROR();
2086     EXPECT_EQ(GL_ZERO, value);
2087     glGetIntegeri_v(GL_BLEND_DST_RGB, 0, &value);
2088     EXPECT_GL_NO_ERROR();
2089     EXPECT_EQ(GL_ONE_MINUS_SRC_ALPHA, value);
2090     glGetIntegeri_v(GL_BLEND_DST_ALPHA, 0, &value);
2091     EXPECT_GL_NO_ERROR();
2092     EXPECT_EQ(GL_ZERO, value);
2093     glGetBooleani_v(GL_COLOR_WRITEMASK, 0, data);
2094     EXPECT_GL_NO_ERROR();
2095     EXPECT_EQ(true, data[0]);
2096     EXPECT_EQ(false, data[1]);
2097     EXPECT_EQ(true, data[2]);
2098     EXPECT_EQ(false, data[3]);
2099 }
2100 
2101 // Test that binding/querying uniforms and attributes with invalid names generates errors
TEST_P(WebGLCompatibilityTest,InvalidAttributeAndUniformNames)2102 TEST_P(WebGLCompatibilityTest, InvalidAttributeAndUniformNames)
2103 {
2104     const std::string validAttribName =
2105         "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
2106     const std::string validUniformName =
2107         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
2108     std::vector<char> invalidSet = {'"', '$', '`', '@', '\''};
2109     if (getClientMajorVersion() < 3)
2110     {
2111         invalidSet.push_back('\\');
2112     }
2113 
2114     std::string vert = "attribute float ";
2115     vert += validAttribName;
2116     vert +=
2117         R"(;
2118 void main()
2119 {
2120     gl_Position = vec4(1.0);
2121 })";
2122 
2123     std::string frag =
2124         R"(precision highp float;
2125 uniform vec4 )";
2126     frag += validUniformName;
2127     // Insert illegal characters into comments
2128     frag +=
2129         R"(;
2130     // $ \" @ /*
2131 void main()
2132 {/*
2133     ` @ $
2134     */gl_FragColor = vec4(1.0);
2135 })";
2136 
2137     ANGLE_GL_PROGRAM(program, vert.c_str(), frag.c_str());
2138     EXPECT_GL_NO_ERROR();
2139 
2140     for (char invalidChar : invalidSet)
2141     {
2142         std::string invalidName = validAttribName + invalidChar;
2143         glGetAttribLocation(program, invalidName.c_str());
2144         EXPECT_GL_ERROR(GL_INVALID_VALUE)
2145             << "glGetAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
2146 
2147         glBindAttribLocation(program, 0, invalidName.c_str());
2148         EXPECT_GL_ERROR(GL_INVALID_VALUE)
2149             << "glBindAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
2150     }
2151 
2152     for (char invalidChar : invalidSet)
2153     {
2154         std::string invalidName = validUniformName + invalidChar;
2155         glGetUniformLocation(program, invalidName.c_str());
2156         EXPECT_GL_ERROR(GL_INVALID_VALUE)
2157             << "glGetUniformLocation unexpectedly succeeded for name \"" << invalidName << "\".";
2158     }
2159 
2160     for (char invalidChar : invalidSet)
2161     {
2162         std::string invalidAttribName = validAttribName + invalidChar;
2163         std::string invalidVert       = "attribute float ";
2164         invalidVert += invalidAttribName;
2165         invalidVert += R"(;,
2166 void main(),
2167 {,
2168     gl_Position = vec4(1.0);,
2169 })";
2170         GLuint program = CompileProgram(invalidVert.c_str(), essl1_shaders::fs::Red());
2171         EXPECT_EQ(0u, program);
2172     }
2173 }
2174 
2175 // Test that line continuation is handled correctly when validating shader source
TEST_P(WebGLCompatibilityTest,ShaderSourceLineContinuation)2176 TEST_P(WebGLCompatibilityTest, ShaderSourceLineContinuation)
2177 {
2178     // With recent changes to WebGL's shader source validation in
2179     // https://github.com/KhronosGroup/WebGL/pull/3206 and follow-ons,
2180     // the backslash character can be used in both WebGL 1.0 and 2.0
2181     // contexts.
2182 
2183     const char *validVert =
2184         R"(#define foo this \
2185     is a test
2186 precision mediump float;
2187 void main()
2188 {
2189     gl_Position = vec4(1.0);
2190 })";
2191 
2192     GLuint program = CompileProgram(validVert, essl1_shaders::fs::Red());
2193     EXPECT_NE(0u, program);
2194     glDeleteProgram(program);
2195 }
2196 
2197 // Test that line continuation is handled correctly when valdiating shader source
TEST_P(WebGL2CompatibilityTest,ShaderSourceLineContinuation)2198 TEST_P(WebGL2CompatibilityTest, ShaderSourceLineContinuation)
2199 {
2200     const char *validVert =
2201         R"(#version 300 es
2202 precision mediump float;
2203 
2204 void main ()
2205 {
2206     float f\
2207 oo = 1.0;
2208     gl_Position = vec4(foo);
2209 })";
2210 
2211     const char *invalidVert =
2212         R"(#version 300 es
2213 precision mediump float;
2214 
2215 void main ()
2216 {
2217     float f\$
2218 oo = 1.0;
2219     gl_Position = vec4(foo);
2220 })";
2221 
2222     GLuint program = CompileProgram(validVert, essl3_shaders::fs::Red());
2223     EXPECT_NE(0u, program);
2224     glDeleteProgram(program);
2225 
2226     program = CompileProgram(invalidVert, essl3_shaders::fs::Red());
2227     EXPECT_EQ(0u, program);
2228 }
2229 
2230 // Tests bindAttribLocations for reserved prefixes and length limits
TEST_P(WebGLCompatibilityTest,BindAttribLocationLimitation)2231 TEST_P(WebGLCompatibilityTest, BindAttribLocationLimitation)
2232 {
2233     constexpr int maxLocStringLength = 256;
2234     const std::string tooLongString(maxLocStringLength + 1, '_');
2235 
2236     glBindAttribLocation(0, 0, "_webgl_var");
2237 
2238     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2239 
2240     glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
2241 
2242     EXPECT_GL_ERROR(GL_INVALID_VALUE);
2243 }
2244 
2245 // Test that having no attributes with a zero divisor is valid in WebGL2
TEST_P(WebGL2CompatibilityTest,InstancedDrawZeroDivisor)2246 TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
2247 {
2248     constexpr char kVS[] =
2249         R"(attribute float a_pos;
2250 void main()
2251 {
2252     gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);
2253 })";
2254 
2255     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
2256 
2257     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
2258     ASSERT_NE(-1, posLocation);
2259 
2260     glUseProgram(program.get());
2261 
2262     GLBuffer buffer;
2263     glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
2264     glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
2265 
2266     glEnableVertexAttribArray(posLocation);
2267     glVertexAttribDivisor(posLocation, 1);
2268 
2269     glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
2270     glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
2271     ASSERT_GL_NO_ERROR();
2272 }
2273 
2274 // Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
TEST_P(WebGLCompatibilityTest,NPOT)2275 TEST_P(WebGLCompatibilityTest, NPOT)
2276 {
2277     EXPECT_FALSE(IsGLExtensionEnabled("GL_OES_texture_npot"));
2278 
2279     // Create a texture and set an NPOT mip 0, should always be acceptable.
2280     GLTexture texture;
2281     glBindTexture(GL_TEXTURE_2D, texture.get());
2282     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2283     ASSERT_GL_NO_ERROR();
2284 
2285     // Try setting an NPOT mip 1 and verify the error if WebGL 1
2286     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2287     if (getClientMajorVersion() < 3)
2288     {
2289         ASSERT_GL_ERROR(GL_INVALID_VALUE);
2290     }
2291     else
2292     {
2293         ASSERT_GL_NO_ERROR();
2294     }
2295 
2296     if (IsGLExtensionRequestable("GL_OES_texture_npot"))
2297     {
2298         glRequestExtensionANGLE("GL_OES_texture_npot");
2299         ASSERT_GL_NO_ERROR();
2300 
2301         // Try again to set NPOT mip 1
2302         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2303         ASSERT_GL_NO_ERROR();
2304     }
2305 }
2306 
2307 template <typename T>
FillTexture2D(GLuint texture,GLsizei width,GLsizei height,const T & onePixelData,GLint level,GLint internalFormat,GLenum format,GLenum type)2308 void FillTexture2D(GLuint texture,
2309                    GLsizei width,
2310                    GLsizei height,
2311                    const T &onePixelData,
2312                    GLint level,
2313                    GLint internalFormat,
2314                    GLenum format,
2315                    GLenum type)
2316 {
2317     std::vector<T> allPixelsData(width * height, onePixelData);
2318 
2319     glBindTexture(GL_TEXTURE_2D, texture);
2320     glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
2321                  allPixelsData.data());
2322     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2323     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2324     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2325     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2326 }
2327 
2328 // Test that unset gl_Position defaults to (0,0,0,0).
TEST_P(WebGLCompatibilityTest,DefaultPosition)2329 TEST_P(WebGLCompatibilityTest, DefaultPosition)
2330 {
2331     // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
2332     // and green otherwise.  The center of each quadrant will be red if and only if all
2333     // four corners are red.
2334     constexpr char kVS[] =
2335         R"(attribute vec3 pos;
2336 varying vec4 color;
2337 void main() {
2338     if (gl_Position == vec4(0,0,0,0)) {
2339         color = vec4(1,0,0,1);
2340     } else {
2341         color = vec4(0,1,0,1);
2342     }
2343     gl_Position = vec4(pos,1);
2344 })";
2345 
2346     constexpr char kFS[] =
2347         R"(precision mediump float;
2348 varying vec4 color;
2349 void main() {
2350     gl_FragColor = color;
2351 })";
2352 
2353     ANGLE_GL_PROGRAM(program, kVS, kFS);
2354     drawQuad(program.get(), "pos", 0.0f, 1.0f, true);
2355     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
2356     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
2357     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
2358     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
2359 }
2360 
2361 // Tests that a rendering feedback loop triggers a GL error under WebGL.
2362 // Based on WebGL test conformance/renderbuffers/feedback-loop.html.
TEST_P(WebGLCompatibilityTest,RenderingFeedbackLoop)2363 TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
2364 {
2365     constexpr char kVS[] =
2366         R"(attribute vec4 a_position;
2367 varying vec2 v_texCoord;
2368 void main() {
2369     gl_Position = a_position;
2370     v_texCoord = (a_position.xy * 0.5) + 0.5;
2371 })";
2372 
2373     constexpr char kFS[] =
2374         R"(precision mediump float;
2375 varying vec2 v_texCoord;
2376 uniform sampler2D u_texture;
2377 void main() {
2378     // Shader swizzles color channels so we can tell if the draw succeeded.
2379     gl_FragColor = texture2D(u_texture, v_texCoord).gbra;
2380 })";
2381 
2382     GLTexture texture;
2383     FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2384 
2385     ASSERT_GL_NO_ERROR();
2386 
2387     GLFramebuffer framebuffer;
2388     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2389     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2390 
2391     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2392 
2393     ANGLE_GL_PROGRAM(program, kVS, kFS);
2394 
2395     GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
2396     ASSERT_NE(-1, uniformLoc);
2397 
2398     glUseProgram(program.get());
2399     glUniform1i(uniformLoc, 0);
2400     glDisable(GL_BLEND);
2401     glDisable(GL_DEPTH_TEST);
2402     ASSERT_GL_NO_ERROR();
2403 
2404     // Drawing with a texture that is also bound to the current framebuffer should fail
2405     glBindTexture(GL_TEXTURE_2D, texture.get());
2406     drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
2407     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2408 
2409     // Ensure that the texture contents did not change after the previous render
2410     glBindFramebuffer(GL_FRAMEBUFFER, 0);
2411     drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
2412     ASSERT_GL_NO_ERROR();
2413     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
2414 
2415     // Drawing when texture is bound to an inactive uniform should succeed
2416     GLTexture texture2;
2417     FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2418 
2419     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2420     glActiveTexture(GL_TEXTURE1);
2421     glBindTexture(GL_TEXTURE_2D, texture.get());
2422     drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
2423     ASSERT_GL_NO_ERROR();
2424     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2425 }
2426 
2427 // Multi-context uses of textures should not cause rendering feedback loops.
TEST_P(WebGLCompatibilityTest,MultiContextNoRenderingFeedbackLoops)2428 TEST_P(WebGLCompatibilityTest, MultiContextNoRenderingFeedbackLoops)
2429 {
2430     constexpr char kUnusedTextureVS[] =
2431         R"(attribute vec4 a_position;
2432 varying vec2 v_texCoord;
2433 void main() {
2434     gl_Position = a_position;
2435     v_texCoord = (a_position.xy * 0.5) + 0.5;
2436 })";
2437 
2438     constexpr char kUnusedTextureFS[] =
2439         R"(precision mediump float;
2440 varying vec2 v_texCoord;
2441 uniform sampler2D u_texture;
2442 void main() {
2443     gl_FragColor = texture2D(u_texture, v_texCoord).rgba;
2444 })";
2445 
2446     ANGLE_GL_PROGRAM(unusedProgram, kUnusedTextureVS, kUnusedTextureFS);
2447 
2448     glUseProgram(unusedProgram.get());
2449     GLint uniformLoc = glGetUniformLocation(unusedProgram.get(), "u_texture");
2450     ASSERT_NE(-1, uniformLoc);
2451     glUniform1i(uniformLoc, 0);
2452 
2453     GLTexture texture;
2454     FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2455     glBindTexture(GL_TEXTURE_2D, texture.get());
2456     // Note that _texture_ is still bound to GL_TEXTURE_2D in this context at this point.
2457 
2458     EGLWindow *window          = getEGLWindow();
2459     EGLDisplay display         = window->getDisplay();
2460     EGLConfig config           = window->getConfig();
2461     EGLSurface surface         = window->getSurface();
2462     EGLint contextAttributes[] = {
2463         EGL_CONTEXT_MAJOR_VERSION_KHR,
2464         GetParam().majorVersion,
2465         EGL_CONTEXT_MINOR_VERSION_KHR,
2466         GetParam().minorVersion,
2467         EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE,
2468         EGL_TRUE,
2469         EGL_NONE,
2470     };
2471     auto context1 = eglGetCurrentContext();
2472     // Create context2, sharing resources with context1.
2473     auto context2 = eglCreateContext(display, config, context1, contextAttributes);
2474     ASSERT_NE(context2, EGL_NO_CONTEXT);
2475     eglMakeCurrent(display, surface, surface, context2);
2476 
2477     constexpr char kVS[] =
2478         R"(attribute vec4 a_position;
2479 void main() {
2480     gl_Position = a_position;
2481 })";
2482 
2483     constexpr char kFS[] =
2484         R"(precision mediump float;
2485 void main() {
2486     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
2487 })";
2488 
2489     ANGLE_GL_PROGRAM(program, kVS, kFS);
2490     glUseProgram(program.get());
2491 
2492     ASSERT_GL_NO_ERROR();
2493 
2494     // Render to the texture in context2.
2495     GLFramebuffer framebuffer;
2496     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2497     // Texture is still a valid name in context2.
2498     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2499     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2500     // There is no rendering feedback loop at this point.
2501 
2502     glDisable(GL_BLEND);
2503     glDisable(GL_DEPTH_TEST);
2504     ASSERT_GL_NO_ERROR();
2505 
2506     drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
2507     ASSERT_GL_NO_ERROR();
2508     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
2509 
2510     eglMakeCurrent(display, surface, surface, context1);
2511     eglDestroyContext(display, context2);
2512 }
2513 
2514 // Test for the max draw buffers and color attachments.
TEST_P(WebGLCompatibilityTest,MaxDrawBuffersAttachmentPoints)2515 TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
2516 {
2517     // This test only applies to ES2.
2518     if (getClientMajorVersion() != 2)
2519     {
2520         return;
2521     }
2522 
2523     GLFramebuffer fbo[2];
2524     glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
2525 
2526     // Test that is valid when we bind with a single attachment point.
2527     GLTexture texture;
2528     glBindTexture(GL_TEXTURE_2D, texture.get());
2529     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2530     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2531     ASSERT_GL_NO_ERROR();
2532 
2533     // Test that enabling the draw buffers extension will allow us to bind with a non-zero
2534     // attachment point.
2535     if (IsGLExtensionRequestable("GL_EXT_draw_buffers"))
2536     {
2537         glRequestExtensionANGLE("GL_EXT_draw_buffers");
2538         EXPECT_GL_NO_ERROR();
2539         EXPECT_TRUE(IsGLExtensionEnabled("GL_EXT_draw_buffers"));
2540 
2541         glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
2542 
2543         GLTexture texture2;
2544         glBindTexture(GL_TEXTURE_2D, texture2.get());
2545         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2546         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
2547                                0);
2548         ASSERT_GL_NO_ERROR();
2549     }
2550 }
2551 
2552 // Test that the offset in the index buffer is forced to be a multiple of the element size
TEST_P(WebGLCompatibilityTest,DrawElementsOffsetRestriction)2553 TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
2554 {
2555     constexpr char kVS[] =
2556         R"(attribute vec3 a_pos;
2557 void main()
2558 {
2559     gl_Position = vec4(a_pos, 1.0);
2560 })";
2561 
2562     ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
2563 
2564     GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
2565     ASSERT_NE(-1, posLocation);
2566     glUseProgram(program.get());
2567 
2568     const auto &vertices = GetQuadVertices();
2569 
2570     GLBuffer vertexBuffer;
2571     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
2572     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
2573                  GL_STATIC_DRAW);
2574 
2575     glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2576     glEnableVertexAttribArray(posLocation);
2577 
2578     GLBuffer indexBuffer;
2579     const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0, 0};
2580     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
2581     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2582 
2583     ASSERT_GL_NO_ERROR();
2584 
2585     const char *zeroIndices = nullptr;
2586 
2587     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
2588     ASSERT_GL_NO_ERROR();
2589 
2590     glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices);
2591     ASSERT_GL_NO_ERROR();
2592 
2593     glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices + 1);
2594     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2595 }
2596 
2597 // Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
2598 // size
TEST_P(WebGLCompatibilityTest,VertexAttribPointerOffsetRestriction)2599 TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
2600 {
2601     const char *zeroOffset = nullptr;
2602 
2603     // Base case, vector of two floats
2604     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
2605     ASSERT_GL_NO_ERROR();
2606 
2607     // Test setting a non-multiple offset
2608     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
2609     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2610     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
2611     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2612     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
2613     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2614 
2615     // Test setting a non-multiple stride
2616     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
2617     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2618     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
2619     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2620     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
2621     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2622 }
2623 
drawBuffersEXTFeedbackLoop(GLuint program,const std::array<GLenum,2> & drawBuffers,GLenum expectedError)2624 void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
2625                                                         const std::array<GLenum, 2> &drawBuffers,
2626                                                         GLenum expectedError)
2627 {
2628     glDrawBuffersEXT(2, drawBuffers.data());
2629 
2630     // Make sure framebuffer is complete before feedback loop detection
2631     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2632 
2633     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2634 
2635     // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2636     // it should be NO_ERROR"
2637     EXPECT_GL_ERROR(expectedError);
2638 }
2639 
2640 // This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
2641 // Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
TEST_P(WebGLCompatibilityTest,RenderingFeedbackLoopWithDrawBuffersEXT)2642 TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
2643 {
2644     constexpr char kVS[] =
2645         R"(attribute vec4 aPosition;
2646 varying vec2 texCoord;
2647 void main() {
2648     gl_Position = aPosition;
2649     texCoord = (aPosition.xy * 0.5) + 0.5;
2650 })";
2651 
2652     constexpr char kFS[] =
2653         R"(#extension GL_EXT_draw_buffers : require
2654 precision mediump float;
2655 uniform sampler2D tex;
2656 varying vec2 texCoord;
2657 void main() {
2658     gl_FragData[0] = texture2D(tex, texCoord);
2659     gl_FragData[1] = texture2D(tex, texCoord);
2660 })";
2661 
2662     GLsizei width  = 8;
2663     GLsizei height = 8;
2664 
2665     // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
2666     // extension and gl_FragData semantics are changed to enforce indexing by zero always.
2667     // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
2668     if (/*!IsGLExtensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
2669     {
2670         // No WEBGL_draw_buffers support -- this is legal.
2671         return;
2672     }
2673 
2674     GLint maxDrawBuffers = 0;
2675     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2676 
2677     // Test skipped because MAX_DRAW_BUFFERS is too small.
2678     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 2);
2679 
2680     ANGLE_GL_PROGRAM(program, kVS, kFS);
2681     glUseProgram(program.get());
2682     glViewport(0, 0, width, height);
2683 
2684     GLTexture tex0;
2685     GLTexture tex1;
2686     GLFramebuffer fbo;
2687     FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2688     FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2689     ASSERT_GL_NO_ERROR();
2690 
2691     glBindTexture(GL_TEXTURE_2D, tex1.get());
2692     GLint texLoc = glGetUniformLocation(program.get(), "tex");
2693     ASSERT_NE(-1, texLoc);
2694     glUniform1i(texLoc, 0);
2695     ASSERT_GL_NO_ERROR();
2696 
2697     // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2698     glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2699     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2700     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
2701 
2702     drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
2703                                GL_INVALID_OPERATION);
2704     drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2705                                GL_INVALID_OPERATION);
2706     // A feedback loop is formed regardless of drawBuffers settings.
2707     drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}},
2708                                GL_INVALID_OPERATION);
2709 }
2710 
2711 // Test tests that texture copying feedback loops are properly rejected in WebGL.
2712 // Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
TEST_P(WebGLCompatibilityTest,TextureCopyingFeedbackLoops)2713 TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
2714 {
2715     // TODO(anglebug.com/5360): Failing on ARM-based Apple DTKs.
2716     ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
2717 
2718     GLTexture texture;
2719     glBindTexture(GL_TEXTURE_2D, texture.get());
2720     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2721     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2722     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2723     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2724     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2725 
2726     GLTexture texture2;
2727     glBindTexture(GL_TEXTURE_2D, texture2.get());
2728     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2729     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2730     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2731     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2732     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2733 
2734     GLFramebuffer framebuffer;
2735     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2736     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2737 
2738     // framebuffer should be FRAMEBUFFER_COMPLETE.
2739     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2740     ASSERT_GL_NO_ERROR();
2741 
2742     // testing copyTexImage2D
2743 
2744     // copyTexImage2D to same texture but different level
2745     glBindTexture(GL_TEXTURE_2D, texture.get());
2746     glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
2747     EXPECT_GL_NO_ERROR();
2748 
2749     // copyTexImage2D to same texture same level, invalid feedback loop
2750     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2751     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2752 
2753     // copyTexImage2D to different texture
2754     glBindTexture(GL_TEXTURE_2D, texture2.get());
2755     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2756     EXPECT_GL_NO_ERROR();
2757 
2758     // testing copyTexSubImage2D
2759 
2760     // copyTexSubImage2D to same texture but different level
2761     glBindTexture(GL_TEXTURE_2D, texture.get());
2762     glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
2763     EXPECT_GL_NO_ERROR();
2764 
2765     // copyTexSubImage2D to same texture same level, invalid feedback loop
2766     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2767     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2768 
2769     // copyTexSubImage2D to different texture
2770     glBindTexture(GL_TEXTURE_2D, texture2.get());
2771     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2772     EXPECT_GL_NO_ERROR();
2773 }
2774 
2775 // Test that copying from mip 1 of a texture to mip 0 works.  When the framebuffer is attached to
2776 // mip 1 of a mip-complete texture, an image with both mips are created.  When copying from the
2777 // framebuffer to mip 0, it is being redefined.
TEST_P(WebGL2CompatibilityTest,CopyMip1ToMip0)2778 TEST_P(WebGL2CompatibilityTest, CopyMip1ToMip0)
2779 {
2780     // http://anglebug.com/4804
2781     ANGLE_SKIP_TEST_IF(IsD3D11());
2782 
2783     // http://anglebug.com/4805
2784     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && (IsWindows() || IsOSX()));
2785 
2786     // TODO(anglebug.com/5360): Failing on ARM64-based Apple DTKs.
2787     ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
2788 
2789     GLFramebuffer framebuffer;
2790     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2791 
2792     GLTexture texture;
2793     glBindTexture(GL_TEXTURE_2D, texture);
2794 
2795     const GLColor mip0[4] = {
2796         GLColor::red,
2797         GLColor::red,
2798         GLColor::red,
2799         GLColor::red,
2800     };
2801     const GLColor mip1[1] = {
2802         GLColor::green,
2803     };
2804 
2805     // Create a complete mip chain in mips 0 to 2
2806     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip0);
2807     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip1);
2808 
2809     // Framebuffer can bind to mip 1, as the texture is mip-complete.
2810     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
2811     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2812 
2813     // Copy to mip 0.  This shouldn't crash.
2814     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
2815     EXPECT_GL_NO_ERROR();
2816 
2817     // The framebuffer is now incomplete.
2818     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
2819                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
2820 
2821     // http://anglebug.com/4802
2822     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA());
2823 
2824     // http://anglebug.com/4803
2825     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsOSX());
2826 
2827     // Bind framebuffer to mip 0 and make sure the copy was done.
2828     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
2829     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2830     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2831 
2832     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
2833 }
2834 
2835 // Test that copying from mip 0 of a texture to mip 1 works.  When the framebuffer is attached to
2836 // mip 0 of a mip-complete texture, an image with both mips are created.  When copying from the
2837 // framebuffer to mip 1, it is being redefined.
TEST_P(WebGL2CompatibilityTest,CopyMip0ToMip1)2838 TEST_P(WebGL2CompatibilityTest, CopyMip0ToMip1)
2839 {
2840     // http://anglebug.com/4805
2841     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
2842 
2843     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAMD() && IsWindows());
2844 
2845     GLFramebuffer framebuffer;
2846     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2847 
2848     GLTexture texture;
2849     glBindTexture(GL_TEXTURE_2D, texture);
2850 
2851     const GLColor mip0[4] = {
2852         GLColor::red,
2853         GLColor::red,
2854         GLColor::red,
2855         GLColor::red,
2856     };
2857     const GLColor mip1[1] = {
2858         GLColor::green,
2859     };
2860 
2861     // Create a complete mip chain in mips 0 to 2
2862     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip0);
2863     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip1);
2864 
2865     // Framebuffer can bind to mip 0, as the texture is mip-complete.
2866     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2867     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2868 
2869     // Copy to mip 1.  This shouldn't crash.
2870     glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
2871     EXPECT_GL_NO_ERROR();
2872 
2873     // The framebuffer is still complete.
2874     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2875     // Make sure mip 0 is untouched.
2876     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2877     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
2878 
2879     // When reading back the framebuffer, the attached texture is not rebased, so the framebuffer
2880     // still sees the 1x1 mip.  The copy is flushed to this mip, which is incorrect.
2881     // http://anglebug.com/4792.
2882     ANGLE_SKIP_TEST_IF(IsVulkan());
2883 
2884     // Bind framebuffer to mip 1 and make sure the copy was done.
2885     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
2886     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
2887     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
2888 
2889     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2890     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
2891 }
2892 
drawBuffersFeedbackLoop(GLuint program,const std::array<GLenum,2> & drawBuffers,GLenum expectedError)2893 void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
2894                                                      const std::array<GLenum, 2> &drawBuffers,
2895                                                      GLenum expectedError)
2896 {
2897     glDrawBuffers(2, drawBuffers.data());
2898 
2899     // Make sure framebuffer is complete before feedback loop detection
2900     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2901 
2902     drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2903 
2904     // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2905     // it should be NO_ERROR"
2906     EXPECT_GL_ERROR(expectedError);
2907 }
2908 
2909 // Tests invariance matching rules between built in varyings.
2910 // Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
TEST_P(WebGLCompatibilityTest,BuiltInInvariant)2911 TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
2912 {
2913     constexpr char kVS[] =
2914         R"(varying vec4 v_varying;
2915 void main()
2916 {
2917     gl_PointSize = 1.0;
2918     gl_Position = v_varying;
2919 })";
2920     constexpr char kFSInvariantGlFragCoord[] =
2921         R"(invariant gl_FragCoord;
2922 void main()
2923 {
2924     gl_FragColor = gl_FragCoord;
2925 })";
2926     constexpr char kFSInvariantGlPointCoord[] =
2927         R"(invariant gl_PointCoord;
2928 void main()
2929 {
2930     gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);
2931 })";
2932 
2933     GLuint program = CompileProgram(kVS, kFSInvariantGlFragCoord);
2934     EXPECT_EQ(0u, program);
2935 
2936     program = CompileProgram(kVS, kFSInvariantGlPointCoord);
2937     EXPECT_EQ(0u, program);
2938 }
2939 
2940 // Tests global namespace conflicts between uniforms and attributes.
2941 // Based on WebGL test conformance/glsl/misc/shaders-with-name-conflicts.html.
TEST_P(WebGLCompatibilityTest,GlobalNamesConflict)2942 TEST_P(WebGLCompatibilityTest, GlobalNamesConflict)
2943 {
2944     constexpr char kVS[] =
2945         R"(attribute vec4 foo;
2946 void main()
2947 {
2948     gl_Position = foo;
2949 })";
2950     constexpr char kFS[] =
2951         R"(precision mediump float;
2952 uniform vec4 foo;
2953 void main()
2954 {
2955     gl_FragColor = foo;
2956 })";
2957 
2958     GLuint program = CompileProgram(kVS, kFS);
2959     EXPECT_NE(0u, program);
2960 }
2961 
2962 // Test dimension and image size validation of compressed textures
TEST_P(WebGLCompatibilityTest,CompressedTextureS3TC)2963 TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
2964 {
2965     if (IsGLExtensionRequestable("GL_EXT_texture_compression_dxt1"))
2966     {
2967         glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
2968     }
2969 
2970     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
2971 
2972     constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
2973 
2974     GLTexture texture;
2975     glBindTexture(GL_TEXTURE_2D, texture);
2976 
2977     // Regular case, verify that it works
2978     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2979                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
2980     ASSERT_GL_NO_ERROR();
2981 
2982     // Test various dimensions that are not valid
2983     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
2984                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
2985     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2986 
2987     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
2988                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
2989     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2990 
2991     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2992                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
2993     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2994 
2995     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2996                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
2997     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2998 
2999     // Test various image sizes that are not valid
3000     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3001                            sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
3002     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3003 
3004     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3005                            sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
3006     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3007 
3008     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
3009                            CompressedImageDXT1);
3010     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3011 
3012     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
3013                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3014     ASSERT_GL_ERROR(GL_INVALID_VALUE);
3015 
3016     // Fill a full mip chain and verify that it works
3017     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
3018                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3019     glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
3020                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3021     glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
3022                            sizeof(CompressedImageDXT1), CompressedImageDXT1);
3023     ASSERT_GL_NO_ERROR();
3024 
3025     glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3026                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3027     ASSERT_GL_NO_ERROR();
3028 
3029     // Test that non-block size sub-uploads are not valid for the 0 mip
3030     glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3031                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3032     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3033 
3034     // Test that non-block size sub-uploads are valid for if they fill the whole mip
3035     glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3036                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3037     glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
3038                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3039     ASSERT_GL_NO_ERROR();
3040 
3041     // Test that if the format miss-matches the texture, an error is generated
3042     glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
3043                               sizeof(CompressedImageDXT1), CompressedImageDXT1);
3044     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3045 }
3046 
TEST_P(WebGLCompatibilityTest,L32FTextures)3047 TEST_P(WebGLCompatibilityTest, L32FTextures)
3048 {
3049     constexpr float textureData[]   = {15.1f, 0.0f, 0.0f, 0.0f};
3050     constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
3051 
3052     for (auto extension : FloatingPointTextureExtensions)
3053     {
3054         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3055         {
3056             glRequestExtensionANGLE(extension);
3057             ASSERT_GL_NO_ERROR();
3058         }
3059 
3060         // Unsized L 32F
3061         {
3062             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3063             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3064             bool render  = false;
3065             TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
3066                                    textureData, readPixelData);
3067         }
3068 
3069         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3070         {
3071             // Sized L 32F
3072             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3073                            IsGLExtensionEnabled("GL_EXT_texture_storage");
3074             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3075             bool render = false;
3076             TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
3077                                    render, textureData, readPixelData);
3078         }
3079     }
3080 }
3081 
TEST_P(WebGLCompatibilityTest,A32FTextures)3082 TEST_P(WebGLCompatibilityTest, A32FTextures)
3083 {
3084     constexpr float textureData[]   = {33.33f, 0.0f, 0.0f, 0.0f};
3085     constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
3086 
3087     for (auto extension : FloatingPointTextureExtensions)
3088     {
3089         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3090         {
3091             glRequestExtensionANGLE(extension);
3092             ASSERT_GL_NO_ERROR();
3093         }
3094 
3095         // Unsized A 32F
3096         {
3097             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3098             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3099             bool render  = false;
3100             TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
3101                                    textureData, readPixelData);
3102         }
3103 
3104         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3105         {
3106             // Sized A 32F
3107             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3108                            IsGLExtensionEnabled("GL_EXT_texture_storage");
3109             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3110             bool render = false;
3111             TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
3112                                    textureData, readPixelData);
3113         }
3114     }
3115 }
3116 
TEST_P(WebGLCompatibilityTest,LA32FTextures)3117 TEST_P(WebGLCompatibilityTest, LA32FTextures)
3118 {
3119     constexpr float textureData[]   = {-0.21f, 15.1f, 0.0f, 0.0f};
3120     constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
3121                                        textureData[1]};
3122 
3123     for (auto extension : FloatingPointTextureExtensions)
3124     {
3125         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3126         {
3127             glRequestExtensionANGLE(extension);
3128             ASSERT_GL_NO_ERROR();
3129         }
3130 
3131         // Unsized LA 32F
3132         {
3133             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3134             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3135             bool render  = false;
3136             TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
3137                                    filter, render, textureData, readPixelData);
3138         }
3139 
3140         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3141         {
3142             // Sized LA 32F
3143             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3144                            IsGLExtensionEnabled("GL_EXT_texture_storage");
3145             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3146             bool render = false;
3147             TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
3148                                    filter, render, textureData, readPixelData);
3149         }
3150     }
3151 }
3152 
TEST_P(WebGLCompatibilityTest,R32FTextures)3153 TEST_P(WebGLCompatibilityTest, R32FTextures)
3154 {
3155     constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
3156 
3157     for (auto extension : FloatingPointTextureExtensions)
3158     {
3159         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3160         {
3161             glRequestExtensionANGLE(extension);
3162             ASSERT_GL_NO_ERROR();
3163         }
3164 
3165         // Unsized R 32F
3166         {
3167             bool texture = IsGLExtensionEnabled("GL_OES_texture_float") &&
3168                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3169             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3170             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3171             TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
3172         }
3173 
3174         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3175         {
3176             // Sized R 32F
3177             bool texture =
3178                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3179                                                    IsGLExtensionEnabled("GL_EXT_texture_rg") &&
3180                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3181             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3182             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3183             TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
3184         }
3185     }
3186 }
3187 
TEST_P(WebGLCompatibilityTest,RG32FTextures)3188 TEST_P(WebGLCompatibilityTest, RG32FTextures)
3189 {
3190     constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
3191 
3192     for (auto extension : FloatingPointTextureExtensions)
3193     {
3194         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3195         {
3196             glRequestExtensionANGLE(extension);
3197             ASSERT_GL_NO_ERROR();
3198         }
3199 
3200         // Unsized RG 32F
3201         {
3202             bool texture = (IsGLExtensionEnabled("GL_OES_texture_float") &&
3203                             IsGLExtensionEnabled("GL_EXT_texture_rg"));
3204             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3205             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3206             TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
3207         }
3208 
3209         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3210         {
3211             // Sized RG 32F
3212             bool texture =
3213                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3214                                                    IsGLExtensionEnabled("GL_EXT_texture_rg") &&
3215                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3216             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3217             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float");
3218             TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
3219         }
3220     }
3221 }
3222 
TEST_P(WebGLCompatibilityTest,RGB32FTextures)3223 TEST_P(WebGLCompatibilityTest, RGB32FTextures)
3224 {
3225     constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
3226 
3227     for (auto extension : FloatingPointTextureExtensions)
3228     {
3229         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3230         {
3231             glRequestExtensionANGLE(extension);
3232             ASSERT_GL_NO_ERROR();
3233         }
3234 
3235         // Unsized RGB 32F
3236         {
3237             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3238             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3239             bool render  = false;
3240             TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
3241         }
3242 
3243         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3244         {
3245             // Sized RGB 32F
3246             bool texture =
3247                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3248                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3249             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3250             bool render = IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
3251             TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
3252                                    data);
3253         }
3254     }
3255 }
3256 
TEST_P(WebGLCompatibilityTest,RGBA32FTextures)3257 TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
3258 {
3259     // http://anglebug.com/5357
3260     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
3261 
3262     constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
3263 
3264     for (auto extension : FloatingPointTextureExtensions)
3265     {
3266         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3267         {
3268             glRequestExtensionANGLE(extension);
3269             ASSERT_GL_NO_ERROR();
3270         }
3271 
3272         // Unsized RGBA 32F
3273         {
3274             bool texture = IsGLExtensionEnabled("GL_OES_texture_float");
3275             bool filter  = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3276             bool render  = false;
3277             TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
3278         }
3279 
3280         if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_EXT_texture_storage"))
3281         {
3282             // Sized RGBA 32F
3283             bool texture =
3284                 (getClientMajorVersion() >= 3) || (IsGLExtensionEnabled("GL_OES_texture_float") &&
3285                                                    IsGLExtensionEnabled("GL_EXT_texture_storage"));
3286             bool filter = IsGLExtensionEnabled("GL_OES_texture_float_linear");
3287             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3288                           IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
3289             TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
3290                                    data);
3291         }
3292     }
3293 }
3294 
3295 // Test that has float color attachment caching works when color attachments change, by calling draw
3296 // command when blending is enabled
TEST_P(WebGLCompatibilityTest,FramebufferFloatColorAttachment)3297 TEST_P(WebGLCompatibilityTest, FramebufferFloatColorAttachment)
3298 {
3299     if (getClientMajorVersion() >= 3)
3300     {
3301         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3302     }
3303     else
3304     {
3305         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_float"));
3306         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
3307     }
3308 
3309     constexpr char kVS[] =
3310         R"(void main()
3311 {
3312     gl_Position = vec4(0, 0, 0, 1);
3313 })";
3314 
3315     constexpr char kFS[] =
3316         R"(void main()
3317 {
3318     gl_FragColor = vec4(0, 1, 0, 1);
3319 })";
3320 
3321     ANGLE_GL_PROGRAM(program, kVS, kFS);
3322     glUseProgram(program);
3323 
3324     glEnable(GL_BLEND);
3325 
3326     GLTexture texture1;
3327     glBindTexture(GL_TEXTURE_2D, texture1);
3328     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3329     EXPECT_GL_NO_ERROR();
3330 
3331     GLTexture texture2;
3332     glBindTexture(GL_TEXTURE_2D, texture2);
3333     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3334     EXPECT_GL_NO_ERROR();
3335 
3336     GLFramebuffer fbo1;
3337     glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
3338     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3339     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3340 
3341     GLFramebuffer fbo2;
3342     glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
3343     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
3344     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3345     glDrawArrays(GL_POINTS, 0, 1);
3346     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3347 
3348     glDisable(GL_BLEND);
3349     glDrawArrays(GL_POINTS, 0, 1);
3350     EXPECT_GL_NO_ERROR();
3351     glEnable(GL_BLEND);
3352 
3353     glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
3354     glDrawArrays(GL_POINTS, 0, 1);
3355 
3356     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0,
3357                            0);  // test unbind
3358     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
3359     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3360 
3361     glDrawArrays(GL_POINTS, 0, 1);
3362     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3363 
3364     glDisable(GL_BLEND);
3365     glDrawArrays(GL_POINTS, 0, 1);
3366     EXPECT_GL_NO_ERROR();
3367     glEnable(GL_BLEND);
3368 
3369     glBindTexture(GL_TEXTURE_2D, texture2);
3370     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3371 
3372     glDrawArrays(GL_POINTS, 0, 1);
3373     EXPECT_GL_NO_ERROR();
3374 }
3375 
3376 // Test that has float color attachment caching works with multiple color attachments bound to a
3377 // Framebuffer
TEST_P(WebGLCompatibilityTest,FramebufferFloatColorAttachmentMRT)3378 TEST_P(WebGLCompatibilityTest, FramebufferFloatColorAttachmentMRT)
3379 {
3380     bool isWebGL2 = getClientMajorVersion() >= 3;
3381     if (isWebGL2)
3382     {
3383         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3384 
3385         constexpr char kVS[] =
3386             R"(#version 300 es
3387 void main()
3388 {
3389     gl_Position = vec4(0, 0, 0, 1);
3390 })";
3391 
3392         constexpr char kFS[] =
3393             R"(#version 300 es
3394 precision lowp float;
3395 layout(location = 0) out vec4 o_color0;
3396 layout(location = 1) out vec4 o_color1;
3397 void main()
3398 {
3399     o_color0 = vec4(1, 0, 0, 1);
3400     o_color1 = vec4(0, 1, 0, 1);
3401 })";
3402 
3403         ANGLE_GL_PROGRAM(program, kVS, kFS);
3404         glUseProgram(program);
3405     }
3406     else
3407     {
3408         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_float"));
3409         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
3410         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_draw_buffers"));
3411 
3412         constexpr char kVS[] =
3413             R"(void main()
3414 {
3415     gl_Position = vec4(0, 0, 0, 1);
3416 })";
3417 
3418         constexpr char kFS[] =
3419             R"(#extension GL_EXT_draw_buffers : require
3420 precision lowp float;
3421 void main()
3422 {
3423     gl_FragData[0] = vec4(1, 0, 0, 1);
3424     gl_FragData[1] = vec4(0, 1, 0, 1);
3425 })";
3426 
3427         ANGLE_GL_PROGRAM(program, kVS, kFS);
3428         glUseProgram(program);
3429     }
3430 
3431     glEnable(GL_BLEND);
3432 
3433     GLTexture texture1;
3434     glBindTexture(GL_TEXTURE_2D, texture1);
3435     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3436     EXPECT_GL_NO_ERROR();
3437 
3438     GLTexture texture2;
3439     glBindTexture(GL_TEXTURE_2D, texture2);
3440     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3441     EXPECT_GL_NO_ERROR();
3442 
3443     GLTexture textureF1;
3444     glBindTexture(GL_TEXTURE_2D, textureF1);
3445     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3446     EXPECT_GL_NO_ERROR();
3447 
3448     GLTexture textureF2;
3449     glBindTexture(GL_TEXTURE_2D, textureF2);
3450     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3451     EXPECT_GL_NO_ERROR();
3452 
3453     GLFramebuffer fbo;
3454     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3455     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3456     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
3457     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3458 
3459     GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
3460     if (isWebGL2)
3461     {
3462         glDrawBuffers(2, drawbuffers);
3463     }
3464     else
3465     {
3466         glDrawBuffersEXT(2, drawbuffers);
3467     }
3468 
3469     glDrawArrays(GL_POINTS, 0, 1);
3470     EXPECT_GL_NO_ERROR();
3471 
3472     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureF1, 0);
3473     glDrawArrays(GL_POINTS, 0, 1);
3474     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3475 
3476     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textureF2, 0);
3477     glDrawArrays(GL_POINTS, 0, 1);
3478     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3479 
3480     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3481     glDrawArrays(GL_POINTS, 0, 1);
3482     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3483 
3484     if (isWebGL2)
3485     {
3486         // WebGL 1 will report a FRAMEBUFFER_UNSUPPORTED for one unsigned_byte and one float
3487         // attachment bound to one FBO at the same time
3488         glDrawBuffers(1, drawbuffers);
3489         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3490         glDrawArrays(GL_POINTS, 0, 1);
3491         EXPECT_GL_NO_ERROR();
3492         glDrawBuffers(2, drawbuffers);
3493     }
3494 
3495     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2, 0);
3496     glDrawArrays(GL_POINTS, 0, 1);
3497     EXPECT_GL_NO_ERROR();
3498 }
3499 
TestBlendColor(const bool shouldClamp)3500 static void TestBlendColor(const bool shouldClamp)
3501 {
3502     auto expected = GLColor32F(5, 0, 0, 0);
3503     glBlendColor(expected.R, expected.G, expected.B, expected.A);
3504     if (shouldClamp)
3505     {
3506         expected.R = 1;
3507     }
3508 
3509     float arr[4] = {};
3510     glGetFloatv(GL_BLEND_COLOR, arr);
3511     const auto actual = GLColor32F(arr[0], arr[1], arr[2], arr[3]);
3512     EXPECT_COLOR_NEAR(expected, actual, 0.001);
3513 }
3514 
3515 // Test if blending of float32 color attachment generates GL_INVALID_OPERATION when
3516 // GL_EXT_float_blend is not enabled
TEST_P(WebGLCompatibilityTest,FloatBlend)3517 TEST_P(WebGLCompatibilityTest, FloatBlend)
3518 {
3519     if (getClientMajorVersion() >= 3)
3520     {
3521         TestBlendColor(false);
3522         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3523     }
3524     else
3525     {
3526         TestBlendColor(true);
3527         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_float"));
3528         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
3529     }
3530 
3531     TestBlendColor(false);
3532 
3533     // -
3534 
3535     TestExtFloatBlend(GL_RGBA32F, GL_FLOAT, false);
3536 
3537     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_float_blend"));
3538     ASSERT_GL_NO_ERROR();
3539 
3540     // D3D9 supports float rendering explicitly, supports blending operations in practice,
3541     // but cannot support float blend colors.
3542     ANGLE_SKIP_TEST_IF(IsD3D9());
3543 
3544     TestExtFloatBlend(GL_RGBA32F, GL_FLOAT, true);
3545 }
3546 
3547 // Test the blending of float16 color attachments
TEST_P(WebGLCompatibilityTest,HalfFloatBlend)3548 TEST_P(WebGLCompatibilityTest, HalfFloatBlend)
3549 {
3550     GLenum internalFormat = GL_RGBA16F;
3551     GLenum type           = GL_FLOAT;
3552     if (getClientMajorVersion() >= 3)
3553     {
3554         TestBlendColor(false);
3555         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3556     }
3557     else
3558     {
3559         TestBlendColor(true);
3560         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_half_float"));
3561         ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_half_float"));
3562         internalFormat = GL_RGBA;
3563         type           = GL_HALF_FLOAT_OES;
3564     }
3565 
3566     TestBlendColor(false);
3567 
3568     // -
3569 
3570     // D3D9 supports float rendering explicitly, supports blending operations in practice,
3571     // but cannot support float blend colors.
3572     ANGLE_SKIP_TEST_IF(IsD3D9());
3573 
3574     TestExtFloatBlend(internalFormat, type, true);
3575 }
3576 
TEST_P(WebGLCompatibilityTest,R16FTextures)3577 TEST_P(WebGLCompatibilityTest, R16FTextures)
3578 {
3579     // http://anglebug.com/5357
3580     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
3581 
3582     constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
3583     const GLushort textureData[]     = {
3584         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3585         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3586 
3587     for (auto extension : FloatingPointTextureExtensions)
3588     {
3589         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3590         {
3591             glRequestExtensionANGLE(extension);
3592             ASSERT_GL_NO_ERROR();
3593         }
3594 
3595         // Unsized R 16F (OES)
3596         {
3597             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3598                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3599             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3600             bool render = false;
3601             TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
3602                                    textureData, readPixelsData);
3603         }
3604 
3605         // Unsized R 16F
3606         {
3607             bool texture = false;
3608             bool filter  = false;
3609             bool render  = false;
3610             TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
3611                                    textureData, readPixelsData);
3612         }
3613 
3614         if (getClientMajorVersion() >= 3)
3615         {
3616             // Sized R 16F
3617             bool texture = true;
3618             bool filter  = true;
3619             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3620                           IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3621             TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
3622                                    textureData, readPixelsData);
3623         }
3624         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3625         {
3626             // Sized R 16F (OES)
3627             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3628                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3629             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3630             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3631             TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
3632                                    textureData, readPixelsData);
3633         }
3634     }
3635 }
3636 
TEST_P(WebGLCompatibilityTest,RG16FTextures)3637 TEST_P(WebGLCompatibilityTest, RG16FTextures)
3638 {
3639     // http://anglebug.com/5357
3640     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
3641 
3642     constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
3643     const GLushort textureData[]     = {
3644         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3645         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3646 
3647     for (auto extension : FloatingPointTextureExtensions)
3648     {
3649         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3650         {
3651             glRequestExtensionANGLE(extension);
3652             ASSERT_GL_NO_ERROR();
3653         }
3654 
3655         // Unsized RG 16F (OES)
3656         {
3657             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3658                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3659             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3660             bool render = false;
3661             TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
3662                                    textureData, readPixelsData);
3663         }
3664 
3665         // Unsized RG 16F
3666         {
3667             bool texture = false;
3668             bool filter  = false;
3669             bool render  = false;
3670             TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
3671                                    textureData, readPixelsData);
3672         }
3673 
3674         if (getClientMajorVersion() >= 3)
3675         {
3676             // Sized RG 16F
3677             bool texture = true;
3678             bool filter  = true;
3679             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3680                           IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3681             TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
3682                                    textureData, readPixelsData);
3683         }
3684         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3685         {
3686             // Sized RG 16F (OES)
3687             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float") &&
3688                            IsGLExtensionEnabled("GL_EXT_texture_rg");
3689             bool filter = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3690             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3691             TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
3692                                    textureData, readPixelsData);
3693         }
3694     }
3695 }
3696 
TEST_P(WebGLCompatibilityTest,RGB16FTextures)3697 TEST_P(WebGLCompatibilityTest, RGB16FTextures)
3698 {
3699     // http://anglebug.com/5357
3700     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
3701 
3702     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
3703 
3704     constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
3705     const GLushort textureData[]     = {
3706         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3707         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3708 
3709     for (auto extension : FloatingPointTextureExtensions)
3710     {
3711         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3712         {
3713             glRequestExtensionANGLE(extension);
3714             ASSERT_GL_NO_ERROR();
3715         }
3716 
3717         // Unsized RGB 16F (OES)
3718         {
3719             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3720             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3721             // WebGL says that Unsized RGB 16F (OES) can be renderable with
3722             // GL_EXT_color_buffer_half_float.
3723             bool render = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3724             TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
3725                                    textureData, readPixelsData);
3726         }
3727 
3728         // Unsized RGB 16F
3729         {
3730             bool texture = false;
3731             bool filter  = false;
3732             bool render  = false;
3733             TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
3734                                    textureData, readPixelsData);
3735         }
3736 
3737         if (getClientMajorVersion() >= 3)
3738         {
3739             // Sized RGB 16F
3740             bool texture = true;
3741             bool filter  = true;
3742             // Renderability of RGB is forbidden by GL_EXT_color_buffer_half_float in WebGL 2.
3743             bool render = false;
3744             TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
3745                                    textureData, readPixelsData);
3746         }
3747         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3748         {
3749             // Sized RGB 16F (OES)
3750             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3751             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3752             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3753             TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
3754                                    textureData, readPixelsData);
3755         }
3756     }
3757 }
3758 
TEST_P(WebGLCompatibilityTest,RGBA16FTextures)3759 TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
3760 {
3761     // http://anglebug.com/5357
3762     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
3763 
3764     ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
3765 
3766     constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
3767     const GLushort textureData[]     = {
3768         gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
3769         gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
3770 
3771     for (auto extension : FloatingPointTextureExtensions)
3772     {
3773         if (strlen(extension) > 0 && IsGLExtensionRequestable(extension))
3774         {
3775             glRequestExtensionANGLE(extension);
3776             ASSERT_GL_NO_ERROR();
3777         }
3778 
3779         // Unsized RGBA 16F (OES)
3780         {
3781             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3782             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3783             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3784             TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
3785                                    textureData, readPixelsData);
3786         }
3787 
3788         // Unsized RGBA 16F
3789         {
3790             bool texture = false;
3791             bool filter  = false;
3792             bool render  = false;
3793             TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
3794                                    textureData, readPixelsData);
3795         }
3796 
3797         if (getClientMajorVersion() >= 3)
3798         {
3799             // Sized RGBA 16F
3800             bool texture = true;
3801             bool filter  = true;
3802             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_float") ||
3803                           IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3804             TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
3805                                    textureData, readPixelsData);
3806         }
3807         else if (IsGLExtensionEnabled("GL_EXT_texture_storage"))
3808         {
3809             // Sized RGBA 16F (OES)
3810             bool texture = IsGLExtensionEnabled("GL_OES_texture_half_float");
3811             bool filter  = IsGLExtensionEnabled("GL_OES_texture_half_float_linear");
3812             bool render  = IsGLExtensionEnabled("GL_EXT_color_buffer_half_float");
3813             TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
3814                                    textureData, readPixelsData);
3815         }
3816     }
3817 }
3818 
3819 // Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
3820 // accepted by glTexImage2D
TEST_P(WebGLCompatibilityTest,SizedRGBA32FFormats)3821 TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
3822 {
3823     // Test skipped because it is only valid for WebGL1 contexts.
3824     ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
3825 
3826     ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_OES_texture_float"));
3827 
3828     glRequestExtensionANGLE("GL_OES_texture_float");
3829     ASSERT_GL_NO_ERROR();
3830 
3831     GLTexture texture;
3832     glBindTexture(GL_TEXTURE_2D, texture);
3833 
3834     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3835     // dEQP implicitly defines error code ordering
3836     EXPECT_GL_ERROR(GL_INVALID_ENUM);
3837 
3838     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
3839     // dEQP implicitly defines error code ordering
3840     EXPECT_GL_ERROR(GL_INVALID_ENUM);
3841 
3842     if (IsGLExtensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
3843     {
3844         glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
3845         ASSERT_GL_NO_ERROR();
3846 
3847         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3848         EXPECT_GL_NO_ERROR();
3849     }
3850 
3851     if (IsGLExtensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
3852     {
3853         glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
3854         ASSERT_GL_NO_ERROR();
3855 
3856         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
3857         EXPECT_GL_NO_ERROR();
3858     }
3859 }
3860 
3861 // Verify GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point.
TEST_P(WebGLCompatibilityTest,DepthStencilAttachment)3862 TEST_P(WebGLCompatibilityTest, DepthStencilAttachment)
3863 {
3864     ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
3865 
3866     // Test that attaching a bound texture succeeds.
3867     GLTexture texture;
3868     glBindTexture(GL_TEXTURE_2D, texture);
3869 
3870     GLFramebuffer fbo;
3871     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3872 
3873     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
3874 
3875     GLint attachmentType = 0;
3876     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3877                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
3878     EXPECT_GL_NO_ERROR();
3879     EXPECT_GLENUM_EQ(GL_TEXTURE, attachmentType);
3880 
3881     // Test when if no attach object at the named attachment point and pname is not OBJECT_TYPE.
3882     GLFramebuffer fbo2;
3883     glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
3884 
3885     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3886                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attachmentType);
3887     EXPECT_GL_ERROR(GL_INVALID_ENUM);
3888 }
3889 
3890 // Verify framebuffer attachments return expected types when in an inconsistant state.
TEST_P(WebGLCompatibilityTest,FramebufferAttachmentConsistancy)3891 TEST_P(WebGLCompatibilityTest, FramebufferAttachmentConsistancy)
3892 {
3893     ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
3894 
3895     GLFramebuffer fbo;
3896     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3897 
3898     GLRenderbuffer rb1;
3899     glBindRenderbuffer(GL_RENDERBUFFER, rb1);
3900 
3901     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb1);
3902 
3903     GLint attachmentType = 0;
3904     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
3905                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
3906 
3907     EXPECT_GL_NO_ERROR();
3908     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
3909 
3910     GLRenderbuffer rb2;
3911     glBindRenderbuffer(GL_RENDERBUFFER, rb2);
3912 
3913     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb2);
3914 
3915     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3916                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
3917 
3918     EXPECT_GL_NO_ERROR();
3919     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
3920 
3921     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb2);
3922 
3923     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
3924                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
3925 
3926     EXPECT_GL_NO_ERROR();
3927     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
3928 
3929     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb2);
3930 
3931     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
3932                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
3933 
3934     EXPECT_GL_NO_ERROR();
3935     EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
3936 }
3937 
3938 // This tests that rendering feedback loops works as expected with WebGL 2.
3939 // Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
TEST_P(WebGL2CompatibilityTest,RenderingFeedbackLoopWithDrawBuffers)3940 TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
3941 {
3942     constexpr char kVS[] =
3943         R"(#version 300 es
3944 in vec4 aPosition;
3945 out vec2 texCoord;
3946 void main() {
3947     gl_Position = aPosition;
3948     texCoord = (aPosition.xy * 0.5) + 0.5;
3949 })";
3950 
3951     constexpr char kFS[] =
3952         R"(#version 300 es
3953 precision mediump float;
3954 uniform sampler2D tex;
3955 in vec2 texCoord;
3956 out vec4 oColor;
3957 void main() {
3958     oColor = texture(tex, texCoord);
3959 })";
3960 
3961     GLsizei width  = 8;
3962     GLsizei height = 8;
3963 
3964     GLint maxDrawBuffers = 0;
3965     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3966     // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
3967     ASSERT_GE(maxDrawBuffers, 2);
3968 
3969     ANGLE_GL_PROGRAM(program, kVS, kFS);
3970     glUseProgram(program.get());
3971     glViewport(0, 0, width, height);
3972 
3973     GLTexture tex0;
3974     GLTexture tex1;
3975     GLFramebuffer fbo;
3976     FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
3977     FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
3978     ASSERT_GL_NO_ERROR();
3979 
3980     glBindTexture(GL_TEXTURE_2D, tex1.get());
3981     GLint texLoc = glGetUniformLocation(program.get(), "tex");
3982     ASSERT_NE(-1, texLoc);
3983     glUniform1i(texLoc, 0);
3984 
3985     // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
3986     glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
3987     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
3988     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
3989     ASSERT_GL_NO_ERROR();
3990 
3991     drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
3992     drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
3993                             GL_INVALID_OPERATION);
3994     // A feedback loop is formed regardless of drawBuffers settings.
3995     drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_INVALID_OPERATION);
3996 }
3997 
3998 // This tests that texture base level for immutable textures is clamped to the valid range, unlike
3999 // for non-immutable textures, for purposes of validation. Related to WebGL test
4000 // conformance2/textures/misc/immutable-tex-render-feedback.html
TEST_P(WebGL2CompatibilityTest,RenderingFeedbackLoopWithImmutableTextureWithOutOfRangeBaseLevel)4001 TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithImmutableTextureWithOutOfRangeBaseLevel)
4002 {
4003     constexpr char kVS[] =
4004         R"(#version 300 es
4005 in vec4 aPosition;
4006 out vec2 texCoord;
4007 void main() {
4008     gl_Position = aPosition;
4009     texCoord = (aPosition.xy * 0.5) + 0.5;
4010 })";
4011 
4012     constexpr char kFS[] =
4013         R"(#version 300 es
4014 precision mediump float;
4015 uniform sampler2D tex;
4016 in vec2 texCoord;
4017 out vec4 oColor;
4018 void main() {
4019     oColor = texture(tex, texCoord);
4020 })";
4021 
4022     GLTexture texture;
4023     glBindTexture(GL_TEXTURE_2D, texture);
4024     glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4);
4025     std::vector<GLColor> texData(4 * 4, GLColor::green);
4026     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, texData.data());
4027     // Set a base level greater than the max level. It should be clamped to the actual max level.
4028     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
4029     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
4030 
4031     ASSERT_GL_NO_ERROR();
4032 
4033     GLFramebuffer framebuffer;
4034     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
4035     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
4036 
4037     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
4038 
4039     ANGLE_GL_PROGRAM(program, kVS, kFS);
4040 
4041     GLint uniformLoc = glGetUniformLocation(program.get(), "tex");
4042     ASSERT_NE(-1, uniformLoc);
4043 
4044     glUseProgram(program.get());
4045     glUniform1i(uniformLoc, 0);
4046     glDisable(GL_BLEND);
4047     glDisable(GL_DEPTH_TEST);
4048     ASSERT_GL_NO_ERROR();
4049 
4050     // Ensure that the texture can be used for rendering.
4051     glBindFramebuffer(GL_FRAMEBUFFER, 0);
4052     glBindTexture(GL_TEXTURE_2D, texture.get());
4053     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4054     ASSERT_GL_NO_ERROR();
4055     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4056 
4057     // Ensure that the texture can't be used to create a feedback loop.
4058     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
4059     glBindTexture(GL_TEXTURE_2D, texture.get());
4060     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4061     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4062 }
4063 
4064 // This test covers detection of rendering feedback loops between the FBO and a depth Texture.
4065 // Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
TEST_P(WebGL2CompatibilityTest,RenderingFeedbackLoopWithDepthStencil)4066 TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
4067 {
4068     constexpr char kVS[] =
4069         R"(#version 300 es
4070 in vec4 aPosition;
4071 out vec2 texCoord;
4072 void main() {
4073     gl_Position = aPosition;
4074     texCoord = (aPosition.xy * 0.5) + 0.5;
4075 })";
4076 
4077     constexpr char kFS[] =
4078         R"(#version 300 es
4079 precision mediump float;
4080 uniform sampler2D tex;
4081 in vec2 texCoord;
4082 out vec4 oColor;
4083 void main() {
4084     oColor = texture(tex, texCoord);
4085 })";
4086 
4087     GLsizei width  = 8;
4088     GLsizei height = 8;
4089 
4090     ANGLE_GL_PROGRAM(program, kVS, kFS);
4091     glUseProgram(program.get());
4092 
4093     glViewport(0, 0, width, height);
4094 
4095     GLint texLoc = glGetUniformLocation(program.get(), "tex");
4096     glUniform1i(texLoc, 0);
4097 
4098     // Create textures and allocate storage
4099     GLTexture tex0;
4100     GLTexture tex1;
4101     GLTexture tex2;
4102     FillTexture2D(tex0.get(), width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
4103     FillTexture2D(tex1.get(), width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
4104                   GL_UNSIGNED_INT);
4105     FillTexture2D(tex2.get(), width, height, 0x40, 0, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
4106                   GL_UNSIGNED_INT_24_8);
4107     ASSERT_GL_NO_ERROR();
4108 
4109     GLFramebuffer fbo;
4110     glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
4111     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
4112 
4113     // Test rendering and sampling feedback loop for depth buffer
4114     glBindTexture(GL_TEXTURE_2D, tex1.get());
4115     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1.get(), 0);
4116     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
4117 
4118     // The same image is used as depth buffer during rendering.
4119     glEnable(GL_DEPTH_TEST);
4120     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4121     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Same image as depth buffer should fail";
4122 
4123     // The same image is used as depth buffer. But depth mask is false.
4124     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4125     glDepthMask(GL_FALSE);
4126     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4127     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Depth writes disabled should still fail";
4128 
4129     // The same image is used as depth buffer. But depth test is not enabled during rendering.
4130     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4131     glDepthMask(GL_TRUE);
4132     glDisable(GL_DEPTH_TEST);
4133     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4134     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Depth read disabled should still fail";
4135 
4136     // Test rendering and sampling feedback loop for stencil buffer
4137     glBindTexture(GL_TEXTURE_2D, tex2.get());
4138     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
4139     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, tex2.get(), 0);
4140     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
4141     constexpr GLint stencilClearValue = 0x40;
4142     glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
4143 
4144     // The same image is used as stencil buffer during rendering.
4145     glEnable(GL_STENCIL_TEST);
4146     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4147     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Same image as stencil buffer should fail";
4148 
4149     // The same image is used as stencil buffer. But stencil mask is zero.
4150     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4151     glStencilMask(0x0);
4152     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4153     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Stencil mask zero should still fail";
4154 
4155     // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
4156     // This is now considered a feedback loop and should generate an error. http://crbug.com/763695
4157     glStencilMask(0xffff);
4158     glDisable(GL_STENCIL_TEST);
4159     drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
4160     EXPECT_GL_ERROR(GL_INVALID_OPERATION) << "Stencil test disabled should still fail";
4161 }
4162 
4163 // The source and the target for CopyTexSubImage3D are the same 3D texture.
4164 // But the level of the 3D texture != the level of the read attachment.
TEST_P(WebGL2CompatibilityTest,NoTextureCopyingFeedbackLoopBetween3DLevels)4165 TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
4166 {
4167     // http://anglebug.com/4092
4168     ANGLE_SKIP_TEST_IF(IsVulkan());
4169     GLTexture texture;
4170     GLFramebuffer framebuffer;
4171 
4172     glBindTexture(GL_TEXTURE_3D, texture.get());
4173     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
4174 
4175     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4176     glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4177     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
4178     ASSERT_GL_NO_ERROR();
4179 
4180     glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
4181     EXPECT_GL_NO_ERROR();
4182 }
4183 
4184 // The source and the target for CopyTexSubImage3D are the same 3D texture.
4185 // But the zoffset of the 3D texture != the layer of the read attachment.
TEST_P(WebGL2CompatibilityTest,NoTextureCopyingFeedbackLoopBetween3DLayers)4186 TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
4187 {
4188     // http://anglebug.com/4092
4189     ANGLE_SKIP_TEST_IF(IsVulkan());
4190     GLTexture texture;
4191     GLFramebuffer framebuffer;
4192 
4193     glBindTexture(GL_TEXTURE_3D, texture.get());
4194     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
4195 
4196     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4197     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 1);
4198     ASSERT_GL_NO_ERROR();
4199 
4200     glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
4201     EXPECT_GL_NO_ERROR();
4202 }
4203 
4204 // The source and the target for CopyTexSubImage3D are the same 3D texture.
4205 // And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
TEST_P(WebGL2CompatibilityTest,TextureCopyingFeedbackLoop3D)4206 TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
4207 {
4208     GLTexture texture;
4209     GLFramebuffer framebuffer;
4210 
4211     glBindTexture(GL_TEXTURE_3D, texture.get());
4212     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
4213 
4214     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4215     glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4216     glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4217     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 1, 0);
4218     ASSERT_GL_NO_ERROR();
4219 
4220     glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
4221     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4222 }
4223 
4224 // Verify that errors are generated when there isn't a defined conversion between the clear type and
4225 // the buffer type.
TEST_P(WebGL2CompatibilityTest,ClearBufferTypeCompatibity)4226 TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
4227 {
4228     // Test skipped for D3D11 because it generates D3D11 runtime warnings.
4229     ANGLE_SKIP_TEST_IF(IsD3D11());
4230 
4231     constexpr float clearFloat[]       = {0.0f, 0.0f, 0.0f, 0.0f};
4232     constexpr int clearInt[]           = {0, 0, 0, 0};
4233     constexpr unsigned int clearUint[] = {0, 0, 0, 0};
4234 
4235     GLTexture texture;
4236     GLFramebuffer framebuffer;
4237 
4238     glBindTexture(GL_TEXTURE_2D, texture.get());
4239     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
4240 
4241     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
4242     ASSERT_GL_NO_ERROR();
4243 
4244     // Unsigned integer buffer
4245     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
4246     ASSERT_GL_NO_ERROR();
4247 
4248     glClearBufferfv(GL_COLOR, 0, clearFloat);
4249     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4250 
4251     glClearBufferiv(GL_COLOR, 0, clearInt);
4252     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4253 
4254     glClearBufferuiv(GL_COLOR, 0, clearUint);
4255     EXPECT_GL_NO_ERROR();
4256 
4257     glClear(GL_COLOR_BUFFER_BIT);
4258     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4259 
4260     // Integer buffer
4261     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
4262     ASSERT_GL_NO_ERROR();
4263 
4264     glClearBufferfv(GL_COLOR, 0, clearFloat);
4265     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4266 
4267     glClearBufferiv(GL_COLOR, 0, clearInt);
4268     EXPECT_GL_NO_ERROR();
4269 
4270     glClearBufferuiv(GL_COLOR, 0, clearUint);
4271     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4272 
4273     glClear(GL_COLOR_BUFFER_BIT);
4274     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4275 
4276     // Float buffer
4277     if (IsGLExtensionRequestable("GL_EXT_color_buffer_float"))
4278     {
4279         glRequestExtensionANGLE("GL_EXT_color_buffer_float");
4280     }
4281 
4282     if (IsGLExtensionEnabled("GL_EXT_color_buffer_float"))
4283     {
4284         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
4285         ASSERT_GL_NO_ERROR();
4286 
4287         glClearBufferfv(GL_COLOR, 0, clearFloat);
4288         EXPECT_GL_NO_ERROR();
4289 
4290         glClearBufferiv(GL_COLOR, 0, clearInt);
4291         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4292 
4293         glClearBufferuiv(GL_COLOR, 0, clearUint);
4294         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4295 
4296         glClear(GL_COLOR_BUFFER_BIT);
4297         EXPECT_GL_NO_ERROR();
4298     }
4299 
4300     // Normalized uint buffer
4301     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4302     ASSERT_GL_NO_ERROR();
4303 
4304     glClearBufferfv(GL_COLOR, 0, clearFloat);
4305     EXPECT_GL_NO_ERROR();
4306 
4307     glClearBufferiv(GL_COLOR, 0, clearInt);
4308     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4309 
4310     glClearBufferuiv(GL_COLOR, 0, clearUint);
4311     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4312 
4313     glClear(GL_COLOR_BUFFER_BIT);
4314     EXPECT_GL_NO_ERROR();
4315 }
4316 
4317 // Test the interaction of WebGL compatibility clears with default framebuffers
TEST_P(WebGL2CompatibilityTest,ClearBufferDefaultFramebuffer)4318 TEST_P(WebGL2CompatibilityTest, ClearBufferDefaultFramebuffer)
4319 {
4320     constexpr float clearFloat[]       = {0.0f, 0.0f, 0.0f, 0.0f};
4321     constexpr int clearInt[]           = {0, 0, 0, 0};
4322     constexpr unsigned int clearUint[] = {0, 0, 0, 0};
4323 
4324     // glClear works as usual, this is also a regression test for a bug where we
4325     // iterated on maxDrawBuffers for default framebuffers, triggering an assert
4326     glClear(GL_COLOR_BUFFER_BIT);
4327     EXPECT_GL_NO_ERROR();
4328 
4329     // Default framebuffers are normalized uints, so only glClearBufferfv works.
4330     glClearBufferfv(GL_COLOR, 0, clearFloat);
4331     EXPECT_GL_NO_ERROR();
4332 
4333     glClearBufferiv(GL_COLOR, 0, clearInt);
4334     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4335 
4336     glClearBufferuiv(GL_COLOR, 0, clearUint);
4337     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4338 }
4339 
4340 // Verify that errors are generate when trying to blit from an image to itself
TEST_P(WebGL2CompatibilityTest,BlitFramebufferSameImage)4341 TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
4342 {
4343     GLTexture textures[2];
4344     glBindTexture(GL_TEXTURE_2D, textures[0]);
4345     glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
4346     glBindTexture(GL_TEXTURE_2D, textures[1]);
4347     glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
4348 
4349     GLRenderbuffer renderbuffers[2];
4350     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
4351     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
4352     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
4353     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
4354 
4355     GLFramebuffer framebuffers[2];
4356     glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
4357     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
4358 
4359     ASSERT_GL_NO_ERROR();
4360 
4361     // Same texture
4362     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
4363                            0);
4364     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
4365                            0);
4366     ASSERT_GL_NO_ERROR();
4367     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4368     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4369 
4370     // Same textures but different renderbuffers
4371     glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4372                               renderbuffers[0]);
4373     glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4374                               renderbuffers[1]);
4375     ASSERT_GL_NO_ERROR();
4376     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
4377     ASSERT_GL_NO_ERROR();
4378     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4379                       GL_NEAREST);
4380     ASSERT_GL_NO_ERROR();
4381     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
4382                       GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4383                       GL_NEAREST);
4384     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4385 
4386     // Same renderbuffers but different textures
4387     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
4388                            0);
4389     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
4390                            0);
4391     glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4392                               renderbuffers[0]);
4393     glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
4394                               renderbuffers[0]);
4395     ASSERT_GL_NO_ERROR();
4396     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4397     ASSERT_GL_NO_ERROR();
4398     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4399                       GL_NEAREST);
4400     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4401     glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
4402                       GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
4403                       GL_NEAREST);
4404     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
4405 }
4406 
4407 // Verify that errors are generated when the fragment shader output doesn't match the bound color
4408 // buffer types
TEST_P(WebGL2CompatibilityTest,FragmentShaderColorBufferTypeMissmatch)4409 TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
4410 {
4411     constexpr char kVS[] =
4412         R"(#version 300 es
4413 void main() {
4414     gl_Position = vec4(0, 0, 0, 1);
4415 })";
4416 
4417     constexpr char kFS[] =
4418         R"(#version 300 es
4419 precision mediump float;
4420 layout(location = 0) out vec4 floatOutput;
4421 layout(location = 1) out uvec4 uintOutput;
4422 layout(location = 2) out ivec4 intOutput;
4423 void main() {
4424     floatOutput = vec4(0, 0, 0, 1);
4425     uintOutput = uvec4(0, 0, 0, 1);
4426     intOutput = ivec4(0, 0, 0, 1);
4427 })";
4428 
4429     ANGLE_GL_PROGRAM(program, kVS, kFS);
4430     glUseProgram(program.get());
4431 
4432     GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
4433     GLuint uintLocation  = glGetFragDataLocation(program, "uintOutput");
4434     GLuint intLocation   = glGetFragDataLocation(program, "intOutput");
4435 
4436     GLFramebuffer fbo;
4437     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4438 
4439     GLRenderbuffer floatRenderbuffer;
4440     glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
4441     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
4442     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
4443                               floatRenderbuffer);
4444 
4445     GLRenderbuffer uintRenderbuffer;
4446     glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
4447     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
4448     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4449                               uintRenderbuffer);
4450 
4451     GLRenderbuffer intRenderbuffer;
4452     glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
4453     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
4454     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4455                               intRenderbuffer);
4456 
4457     ASSERT_GL_NO_ERROR();
4458 
4459     GLint maxDrawBuffers = 0;
4460     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
4461     std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
4462     drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
4463     drawBuffers[uintLocation]  = GL_COLOR_ATTACHMENT0 + uintLocation;
4464     drawBuffers[intLocation]   = GL_COLOR_ATTACHMENT0 + intLocation;
4465 
4466     glDrawBuffers(maxDrawBuffers, drawBuffers.data());
4467 
4468     // Check that the correct case generates no errors
4469     glDrawArrays(GL_TRIANGLES, 0, 6);
4470     EXPECT_GL_NO_ERROR();
4471 
4472     // Unbind some buffers and verify that there are still no errors
4473     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4474                               0);
4475     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4476                               0);
4477     glDrawArrays(GL_TRIANGLES, 0, 6);
4478     EXPECT_GL_NO_ERROR();
4479 
4480     // Swap the int and uint buffers to and verify that an error is generated
4481     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4482                               intRenderbuffer);
4483     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4484                               uintRenderbuffer);
4485     glDrawArrays(GL_TRIANGLES, 0, 6);
4486     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4487 
4488     // Swap the float and uint buffers to and verify that an error is generated
4489     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
4490                               floatRenderbuffer);
4491     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
4492                               uintRenderbuffer);
4493     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
4494                               intRenderbuffer);
4495     glDrawArrays(GL_TRIANGLES, 0, 6);
4496     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4497 }
4498 
4499 // Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
4500 // types
TEST_P(WebGL2CompatibilityTest,VertexShaderAttributeTypeMismatch)4501 TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMismatch)
4502 {
4503     constexpr char kVS[] =
4504         R"(#version 300 es
4505 in vec4 floatInput;
4506 in uvec4 uintInput;
4507 in ivec4 intInput;
4508 void main() {
4509     gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);
4510 })";
4511 
4512     constexpr char kFS[] =
4513         R"(#version 300 es
4514 precision mediump float;
4515 out vec4 outputColor;
4516 void main() {
4517     outputColor = vec4(0, 0, 0, 1);
4518 })";
4519 
4520     ANGLE_GL_PROGRAM(program, kVS, kFS);
4521     glUseProgram(program.get());
4522 
4523     GLint floatLocation = glGetAttribLocation(program, "floatInput");
4524     GLint uintLocation  = glGetAttribLocation(program, "uintInput");
4525     GLint intLocation   = glGetAttribLocation(program, "intInput");
4526 
4527     // Default attributes are of float types
4528     glDrawArrays(GL_TRIANGLES, 0, 6);
4529     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4530 
4531     // Set the default attributes to the correct types, should succeed
4532     glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
4533     glVertexAttribI4i(intLocation, 0, 0, 0, 1);
4534     glDrawArrays(GL_TRIANGLES, 0, 6);
4535     EXPECT_GL_NO_ERROR();
4536 
4537     // Change the default float attribute to an integer, should fail
4538     glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
4539     glDrawArrays(GL_TRIANGLES, 0, 6);
4540     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4541 
4542     // Use a buffer for some attributes
4543     GLBuffer buffer;
4544     glBindBuffer(GL_ARRAY_BUFFER, buffer);
4545     glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
4546     glEnableVertexAttribArray(floatLocation);
4547     glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
4548     glDrawArrays(GL_TRIANGLES, 0, 6);
4549     EXPECT_GL_NO_ERROR();
4550 
4551     // Use a float pointer attrib for a uint input
4552     glEnableVertexAttribArray(uintLocation);
4553     glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
4554     glDrawArrays(GL_TRIANGLES, 0, 6);
4555     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4556 
4557     // Use a uint pointer for the uint input
4558     glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
4559     glDrawArrays(GL_TRIANGLES, 0, 6);
4560     EXPECT_GL_NO_ERROR();
4561 }
4562 
4563 // Test that it's not possible to query the non-zero color attachments without the drawbuffers
4564 // extension in WebGL1
TEST_P(WebGLCompatibilityTest,FramebufferAttachmentQuery)4565 TEST_P(WebGLCompatibilityTest, FramebufferAttachmentQuery)
4566 {
4567     ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
4568     ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_EXT_draw_buffers"));
4569 
4570     GLFramebuffer fbo;
4571     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4572     EXPECT_GL_NO_ERROR();
4573 
4574     GLint result;
4575     glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
4576                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &result);
4577     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4578 
4579     GLRenderbuffer renderbuffer;
4580     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
4581     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
4582     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, renderbuffer);
4583     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4584 }
4585 
4586 // Tests WebGL reports INVALID_OPERATION for mismatch of drawbuffers and fragment output
TEST_P(WebGLCompatibilityTest,DrawBuffers)4587 TEST_P(WebGLCompatibilityTest, DrawBuffers)
4588 {
4589     // Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
4590     ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
4591 
4592     // Make sure we can use at least 4 attachments for the tests.
4593     bool useEXT = false;
4594     if (getClientMajorVersion() < 3)
4595     {
4596         ANGLE_SKIP_TEST_IF(!IsGLExtensionRequestable("GL_EXT_draw_buffers"));
4597 
4598         glRequestExtensionANGLE("GL_EXT_draw_buffers");
4599         useEXT = true;
4600         EXPECT_GL_NO_ERROR();
4601     }
4602 
4603     GLint maxDrawBuffers = 0;
4604     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
4605     // Test skipped because MAX_DRAW_BUFFERS is too small.
4606     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
4607 
4608     // Clears all the renderbuffers to red.
4609     auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
4610         GLFramebuffer clearFBO;
4611         glBindFramebuffer(GL_FRAMEBUFFER, clearFBO);
4612 
4613         glClearColor(1, 0, 0, 1);
4614         for (int i = 0; i < 4; ++i)
4615         {
4616             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
4617                                       renderbuffers[i]);
4618             glClear(GL_COLOR_BUFFER_BIT);
4619         }
4620         ASSERT_GL_NO_ERROR();
4621     };
4622 
4623     // Checks that the renderbuffers specified by mask have the correct color
4624     auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
4625         GLFramebuffer readFBO;
4626         glBindFramebuffer(GL_FRAMEBUFFER, readFBO);
4627 
4628         for (int attachmentIndex = 0; attachmentIndex < 4; ++attachmentIndex)
4629         {
4630             if (mask & (1 << attachmentIndex))
4631             {
4632                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
4633                                           renderbuffers[attachmentIndex]);
4634                 EXPECT_PIXEL_COLOR_EQ(0, 0, color) << "attachment " << attachmentIndex;
4635             }
4636         }
4637         ASSERT_GL_NO_ERROR();
4638     };
4639 
4640     // Depending on whether we are using the extension or ES3, a different entrypoint must be called
4641     auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
4642         if (useEXT)
4643         {
4644             glDrawBuffersEXT(numBuffers, buffers);
4645         }
4646         else
4647         {
4648             glDrawBuffers(numBuffers, buffers);
4649         }
4650     };
4651 
4652     // Initialized the test framebuffer
4653     GLFramebuffer drawFBO;
4654     glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4655 
4656     GLRenderbuffer renderbuffers[4];
4657     for (int i = 0; i < 4; ++i)
4658     {
4659         glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
4660         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
4661         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
4662                                   renderbuffers[i]);
4663     }
4664 
4665     ASSERT_GL_NO_ERROR();
4666 
4667     GLenum allDrawBuffers[] = {
4668         GL_COLOR_ATTACHMENT0,
4669         GL_COLOR_ATTACHMENT1,
4670         GL_COLOR_ATTACHMENT2,
4671         GL_COLOR_ATTACHMENT3,
4672     };
4673 
4674     GLenum halfDrawBuffers[] = {
4675         GL_NONE,
4676         GL_COLOR_ATTACHMENT1,
4677         GL_NONE,
4678         GL_COLOR_ATTACHMENT3,
4679     };
4680 
4681     // Test that when using gl_FragColor with no-array
4682     const char *fragESSL1 =
4683         R"(precision highp float;
4684 void main()
4685 {
4686     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
4687 })";
4688     ANGLE_GL_PROGRAM(programESSL1, essl1_shaders::vs::Simple(), fragESSL1);
4689 
4690     {
4691         glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4692         DrawBuffers(useEXT, 4, allDrawBuffers);
4693         drawQuad(programESSL1, essl1_shaders::PositionAttrib(), 0.5, 1.0, true);
4694         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4695     }
4696 
4697     // Test what happens when rendering to a subset of the outputs. There is a behavior difference
4698     // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
4699     // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
4700     // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
4701     // attachments not declared in the shader should not be written to.
4702     const char *positionAttrib;
4703     const char *writeOddOutputsVert;
4704     const char *writeOddOutputsFrag;
4705     if (useEXT)
4706     {
4707         positionAttrib      = essl1_shaders::PositionAttrib();
4708         writeOddOutputsVert = essl1_shaders::vs::Simple();
4709         writeOddOutputsFrag =
4710             R"(#extension GL_EXT_draw_buffers : require
4711 precision highp float;
4712 void main()
4713 {
4714     gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);
4715     gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);
4716 })";
4717     }
4718     else
4719     {
4720         positionAttrib      = essl3_shaders::PositionAttrib();
4721         writeOddOutputsVert = essl3_shaders::vs::Simple();
4722         writeOddOutputsFrag =
4723             R"(#version 300 es
4724 precision highp float;
4725 layout(location = 1) out vec4 output1;
4726 layout(location = 3) out vec4 output2;
4727 void main()
4728 {
4729     output1 = vec4(0.0, 1.0, 0.0, 1.0);
4730     output2 = vec4(0.0, 1.0, 0.0, 1.0);
4731 })";
4732     }
4733     ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
4734 
4735     // Test that attachments not written to get the "unwritten" color (useEXT)
4736     // Or INVALID_OPERATION is generated if there's active draw buffer receive no output
4737     {
4738         ClearEverythingToRed(renderbuffers);
4739 
4740         glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4741         DrawBuffers(useEXT, 4, allDrawBuffers);
4742         drawQuad(writeOddOutputsProgram, positionAttrib, 0.5, 1.0, true);
4743 
4744         if (useEXT)
4745         {
4746             ASSERT_GL_NO_ERROR();
4747             CheckColors(renderbuffers, 0b1010, GLColor::green);
4748             // In the extension, when an attachment isn't written to, it should get 0's
4749             CheckColors(renderbuffers, 0b0101, GLColor(0, 0, 0, 0));
4750         }
4751         else
4752         {
4753             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4754         }
4755     }
4756 
4757     // TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
4758     // http://anglebug.com/3423
4759     ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
4760 
4761     // Test that attachments written to get the correct color from shader output but that even when
4762     // the extension is used, disabled attachments are not written at all and stay red.
4763     {
4764         ClearEverythingToRed(renderbuffers);
4765 
4766         glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
4767         DrawBuffers(useEXT, 4, halfDrawBuffers);
4768         drawQuad(writeOddOutputsProgram, positionAttrib, 0.5, 1.0, true);
4769         ASSERT_GL_NO_ERROR();
4770 
4771         CheckColors(renderbuffers, 0b1010, GLColor::green);
4772         CheckColors(renderbuffers, 0b0101, GLColor::red);
4773     }
4774 }
4775 
4776 // Test that it's possible to generate mipmaps on unsized floating point textures once the
4777 // extensions have been enabled
TEST_P(WebGLCompatibilityTest,GenerateMipmapUnsizedFloatingPointTexture)4778 TEST_P(WebGLCompatibilityTest, GenerateMipmapUnsizedFloatingPointTexture)
4779 {
4780     glRequestExtensionANGLE("GL_OES_texture_float");
4781     glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
4782     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
4783     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"));
4784 
4785     GLTexture texture;
4786     glBindTexture(GL_TEXTURE_2D, texture);
4787 
4788     constexpr GLColor32F data[4] = {
4789         kFloatRed,
4790         kFloatRed,
4791         kFloatGreen,
4792         kFloatBlue,
4793     };
4794     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_FLOAT, data);
4795     ASSERT_GL_NO_ERROR();
4796 
4797     glGenerateMipmap(GL_TEXTURE_2D);
4798     EXPECT_GL_NO_ERROR();
4799 }
4800 // Test that it's possible to generate mipmaps on unsized floating point textures once the
4801 // extensions have been enabled
TEST_P(WebGLCompatibilityTest,GenerateMipmapSizedFloatingPointTexture)4802 TEST_P(WebGLCompatibilityTest, GenerateMipmapSizedFloatingPointTexture)
4803 {
4804     if (IsGLExtensionRequestable("GL_OES_texture_float"))
4805     {
4806         glRequestExtensionANGLE("GL_OES_texture_float");
4807     }
4808     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_float"));
4809 
4810     if (IsGLExtensionRequestable("GL_EXT_texture_storage"))
4811     {
4812         glRequestExtensionANGLE("GL_EXT_texture_storage");
4813     }
4814     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
4815 
4816     GLTexture texture;
4817     glBindTexture(GL_TEXTURE_2D, texture);
4818 
4819     constexpr GLColor32F data[4] = {
4820         kFloatRed,
4821         kFloatRed,
4822         kFloatGreen,
4823         kFloatBlue,
4824     };
4825     glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA32F, 2, 2);
4826     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_FLOAT, data);
4827     ASSERT_GL_NO_ERROR();
4828 
4829     glGenerateMipmap(GL_TEXTURE_2D);
4830     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4831 
4832     if (IsGLExtensionRequestable("GL_EXT_color_buffer_float"))
4833     {
4834         // Format is renderable but not filterable
4835         glRequestExtensionANGLE("GL_EXT_color_buffer_float");
4836         glGenerateMipmap(GL_TEXTURE_2D);
4837         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4838     }
4839 
4840     if (IsGLExtensionRequestable("GL_EXT_color_buffer_float_linear"))
4841     {
4842         // Format is renderable but not filterable
4843         glRequestExtensionANGLE("GL_EXT_color_buffer_float_linear");
4844 
4845         if (IsGLExtensionEnabled("GL_EXT_color_buffer_float"))
4846         {
4847             // Format is filterable and renderable
4848             glGenerateMipmap(GL_TEXTURE_2D);
4849             EXPECT_GL_NO_ERROR();
4850         }
4851         else
4852         {
4853             // Format is filterable but not renderable
4854             glGenerateMipmap(GL_TEXTURE_2D);
4855             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4856         }
4857     }
4858 }
4859 
4860 // Verify that a texture format is only allowed with extension enabled.
validateTexImageExtensionFormat(GLenum format,const std::string & extName)4861 void WebGLCompatibilityTest::validateTexImageExtensionFormat(GLenum format,
4862                                                              const std::string &extName)
4863 {
4864     // Verify texture format fails by default.
4865     glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, GL_UNSIGNED_BYTE, nullptr);
4866     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4867 
4868     if (IsGLExtensionRequestable(extName))
4869     {
4870         // Verify texture format is allowed once extension is enabled.
4871         glRequestExtensionANGLE(extName.c_str());
4872         EXPECT_TRUE(IsGLExtensionEnabled(extName));
4873 
4874         glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, GL_UNSIGNED_BYTE, nullptr);
4875         ASSERT_GL_NO_ERROR();
4876     }
4877 }
4878 
4879 // Test enabling various non-compressed texture format extensions
TEST_P(WebGLCompatibilityTest,EnableTextureFormatExtensions)4880 TEST_P(WebGLCompatibilityTest, EnableTextureFormatExtensions)
4881 {
4882     ANGLE_SKIP_TEST_IF(IsOzone());
4883     ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
4884 
4885     GLTexture texture;
4886     glBindTexture(GL_TEXTURE_2D, texture.get());
4887 
4888     // Verify valid format is allowed.
4889     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
4890     ASSERT_GL_NO_ERROR();
4891 
4892     // Verify invalid format fails.
4893     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA32F, GL_UNSIGNED_BYTE, nullptr);
4894     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4895 
4896     // Verify formats from enableable extensions.
4897     if (!IsOpenGLES())
4898     {
4899         validateTexImageExtensionFormat(GL_RED_EXT, "GL_EXT_texture_rg");
4900     }
4901 
4902     validateTexImageExtensionFormat(GL_SRGB_EXT, "GL_EXT_texture_sRGB");
4903     validateTexImageExtensionFormat(GL_BGRA_EXT, "GL_EXT_texture_format_BGRA8888");
4904 }
4905 
validateCompressedTexImageExtensionFormat(GLenum format,GLsizei width,GLsizei height,GLsizei blockSize,const std::string & extName,bool subImageAllowed)4906 void WebGLCompatibilityTest::validateCompressedTexImageExtensionFormat(GLenum format,
4907                                                                        GLsizei width,
4908                                                                        GLsizei height,
4909                                                                        GLsizei blockSize,
4910                                                                        const std::string &extName,
4911                                                                        bool subImageAllowed)
4912 {
4913     std::vector<GLubyte> data(blockSize, 0u);
4914 
4915     GLTexture texture;
4916     glBindTexture(GL_TEXTURE_2D, texture.get());
4917 
4918     // Verify texture format fails by default.
4919     glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, blockSize, data.data());
4920     EXPECT_GL_ERROR(GL_INVALID_ENUM);
4921 
4922     if (IsGLExtensionRequestable(extName))
4923     {
4924         // Verify texture format is allowed once extension is enabled.
4925         glRequestExtensionANGLE(extName.c_str());
4926         EXPECT_TRUE(IsGLExtensionEnabled(extName));
4927 
4928         glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, blockSize, data.data());
4929         EXPECT_GL_NO_ERROR();
4930 
4931         glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, blockSize,
4932                                   data.data());
4933         if (subImageAllowed)
4934         {
4935             EXPECT_GL_NO_ERROR();
4936         }
4937         else
4938         {
4939             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
4940         }
4941     }
4942 }
4943 
4944 // Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGB_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1RGB)4945 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGB)
4946 {
4947     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 8,
4948                                               "GL_EXT_texture_compression_dxt1", true);
4949 }
4950 
4951 // Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1RGBA)4952 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGBA)
4953 {
4954     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 8,
4955                                               "GL_EXT_texture_compression_dxt1", true);
4956 }
4957 
4958 // Test enabling GL_ANGLE_texture_compression_dxt3
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT3)4959 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT3)
4960 {
4961     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, 4, 4, 16,
4962                                               "GL_ANGLE_texture_compression_dxt3", true);
4963 }
4964 
4965 // Test enabling GL_ANGLE_texture_compression_dxt5
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT5)4966 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT5)
4967 {
4968     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, 4, 4, 16,
4969                                               "GL_ANGLE_texture_compression_dxt5", true);
4970 }
4971 
4972 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1SRGB)4973 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1SRGB)
4974 {
4975     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 4, 4, 8,
4976                                               "GL_EXT_texture_compression_s3tc_srgb", true);
4977 }
4978 
4979 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT1SRGBA)4980 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1SRGBA)
4981 {
4982     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 4, 4, 8,
4983                                               "GL_EXT_texture_compression_s3tc_srgb", true);
4984 }
4985 
4986 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT3SRGBA)4987 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT3SRGBA)
4988 {
4989     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 4, 4, 16,
4990                                               "GL_EXT_texture_compression_s3tc_srgb", true);
4991 }
4992 
4993 // Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionDXT5SRGBA)4994 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT5SRGBA)
4995 {
4996     validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 4, 4, 16,
4997                                               "GL_EXT_texture_compression_s3tc_srgb", true);
4998 }
4999 
5000 // Test enabling GL_OES_compressed_ETC1_RGB8_texture
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionETC1)5001 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionETC1)
5002 {
5003     validateCompressedTexImageExtensionFormat(
5004         GL_ETC1_RGB8_OES, 4, 4, 8, "GL_OES_compressed_ETC1_RGB8_texture",
5005         IsGLExtensionEnabled("GL_EXT_compressed_ETC1_RGB8_sub_texture"));
5006 }
5007 
5008 // Test enabling GL_ANGLE_lossy_etc_decode
TEST_P(WebGLCompatibilityTest,EnableCompressedTextureExtensionLossyDecode)5009 TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionLossyDecode)
5010 {
5011     validateCompressedTexImageExtensionFormat(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 4, 4, 8,
5012                                               "GL_ANGLE_lossy_etc_decode", true);
5013 }
5014 
5015 // Reject attempts to allocate too-large arrays in shaders.
5016 // This is an implementation-defined limit - crbug.com/1220237 .
TEST_P(WebGLCompatibilityTest,ValidateArraySizes)5017 TEST_P(WebGLCompatibilityTest, ValidateArraySizes)
5018 {
5019     // Note: on macOS with ANGLE's OpenGL backend, getting anywhere
5020     // close to this limit causes pathologically slow shader
5021     // compilation in the driver. For the "ok" case, therefore, use a
5022     // fairly small array.
5023     constexpr char kVSArrayOK[] =
5024         R"(varying vec4 color;
5025 const int array_size = 1000;
5026 void main()
5027 {
5028     mat2 array[array_size];
5029     if (array[0][0][0] == 2.0)
5030         color = vec4(0.0, 1.0, 0.0, 1.0);
5031     else
5032         color = vec4(1.0, 0.0, 0.0, 1.0);
5033 })";
5034 
5035     constexpr char kVSArrayTooLarge[] =
5036         R"(varying vec4 color;
5037 // 2 GB / 32 aligned bytes per mat2 = 67108864
5038 const int array_size = 67108865;
5039 void main()
5040 {
5041     mat2 array[array_size];
5042     if (array[0][0][0] == 2.0)
5043         color = vec4(0.0, 1.0, 0.0, 1.0);
5044     else
5045         color = vec4(1.0, 0.0, 0.0, 1.0);
5046 })";
5047 
5048     constexpr char kVSArrayMuchTooLarge[] =
5049         R"(varying vec4 color;
5050 const int array_size = 795418649;
5051 void main()
5052 {
5053     mat2 array[array_size];
5054     if (array[0][0][0] == 2.0)
5055         color = vec4(0.0, 1.0, 0.0, 1.0);
5056     else
5057         color = vec4(1.0, 0.0, 0.0, 1.0);
5058 })";
5059 
5060     constexpr char kFS[] =
5061         R"(precision mediump float;
5062 varying vec4 color;
5063 void main()
5064 {
5065     gl_FragColor = vec4(color.r - 0.5, 0.0, 0.0, 1.0);
5066 })";
5067 
5068     GLuint program = CompileProgram(kVSArrayOK, kFS);
5069     EXPECT_NE(0u, program);
5070 
5071     program = CompileProgram(kVSArrayTooLarge, kFS);
5072     EXPECT_EQ(0u, program);
5073 
5074     program = CompileProgram(kVSArrayMuchTooLarge, kFS);
5075     EXPECT_EQ(0u, program);
5076 }
5077 
5078 // Reject attempts to allocate too-large structs in shaders.
5079 // This is an implementation-defined limit - crbug.com/1220237 .
TEST_P(WebGLCompatibilityTest,ValidateStructSizes)5080 TEST_P(WebGLCompatibilityTest, ValidateStructSizes)
5081 {
5082     // Note: on macOS with ANGLE's OpenGL backend, getting anywhere
5083     // close to this limit causes pathologically slow shader
5084     // compilation in the driver. For this reason, only perform a
5085     // negative test.
5086     constexpr char kFSStructTooLarge[] =
5087         R"(precision mediump float;
5088 struct Light {
5089 // 2 GB / 32 aligned bytes per mat2 = 67108864
5090 mat2 array[67108865];
5091 };
5092 
5093 uniform Light light;
5094 
5095 void main()
5096 {
5097     if (light.array[0][0][0] == 2.0)
5098         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5099     else
5100         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5101 })";
5102 
5103     GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFSStructTooLarge);
5104     EXPECT_EQ(0u, program);
5105 }
5106 
5107 // Linking should fail when corresponding vertex/fragment uniform blocks have different precision
5108 // qualifiers.
TEST_P(WebGL2CompatibilityTest,UniformBlockPrecisionMismatch)5109 TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
5110 {
5111     constexpr char kVS[] =
5112         R"(#version 300 es
5113 uniform Block { mediump vec4 val; };
5114 void main() { gl_Position = val; })";
5115     constexpr char kFS[] =
5116         R"(#version 300 es
5117 uniform Block { highp vec4 val; };
5118 out highp vec4 out_FragColor;
5119 void main() { out_FragColor = val; })";
5120 
5121     GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
5122     ASSERT_NE(0u, vs);
5123     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
5124     ASSERT_NE(0u, fs);
5125 
5126     GLuint program = glCreateProgram();
5127 
5128     glAttachShader(program, vs);
5129     glDeleteShader(vs);
5130     glAttachShader(program, fs);
5131     glDeleteShader(fs);
5132 
5133     glLinkProgram(program);
5134     GLint linkStatus;
5135     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
5136     ASSERT_EQ(0, linkStatus);
5137 
5138     glDeleteProgram(program);
5139 }
5140 
5141 // Test no attribute vertex shaders
TEST_P(WebGL2CompatibilityTest,NoAttributeVertexShader)5142 TEST_P(WebGL2CompatibilityTest, NoAttributeVertexShader)
5143 {
5144     constexpr char kVS[] =
5145         R"(#version 300 es
5146 void main()
5147 {
5148 
5149     ivec2 xy = ivec2(gl_VertexID % 2, (gl_VertexID / 2 + gl_VertexID / 3) % 2);
5150     gl_Position = vec4(vec2(xy) * 2. - 1., 0, 1);
5151 })";
5152 
5153     ANGLE_GL_PROGRAM(program, kVS, essl3_shaders::fs::Red());
5154     glUseProgram(program);
5155 
5156     glDrawArrays(GL_TRIANGLES, 0, 6);
5157     ASSERT_GL_NO_ERROR();
5158     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
5159 }
5160 
5161 // Tests bindAttribLocations for length limit
TEST_P(WebGL2CompatibilityTest,BindAttribLocationLimitation)5162 TEST_P(WebGL2CompatibilityTest, BindAttribLocationLimitation)
5163 {
5164     constexpr int maxLocStringLength = 1024;
5165     const std::string tooLongString(maxLocStringLength + 1, '_');
5166 
5167     glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
5168 
5169     EXPECT_GL_ERROR(GL_INVALID_VALUE);
5170 }
5171 
5172 // Covers a bug in transform feedback loop detection.
TEST_P(WebGL2CompatibilityTest,TransformFeedbackCheckNullDeref)5173 TEST_P(WebGL2CompatibilityTest, TransformFeedbackCheckNullDeref)
5174 {
5175     constexpr char kVS[] = R"(attribute vec4 color; void main() { color.r; })";
5176     constexpr char kFS[] = R"(void main(){})";
5177     ANGLE_GL_PROGRAM(program, kVS, kFS);
5178     glUseProgram(program);
5179 
5180     glEnableVertexAttribArray(0);
5181     glDrawArrays(GL_POINTS, 0, 1);
5182 
5183     // This should fail because it is trying to pull a vertex with no buffer.
5184     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5185 
5186     GLBuffer buffer;
5187     glBindBuffer(GL_ARRAY_BUFFER, buffer);
5188     glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
5189 
5190     // This should fail because it is trying to pull a vertex from an empty buffer.
5191     glDrawArrays(GL_POINTS, 0, 1);
5192     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5193 }
5194 
5195 // We should forbid two transform feedback outputs going to the same buffer.
TEST_P(WebGL2CompatibilityTest,TransformFeedbackDoubleBinding)5196 TEST_P(WebGL2CompatibilityTest, TransformFeedbackDoubleBinding)
5197 {
5198     constexpr char kVS[] =
5199         R"(attribute float a; varying float b; varying float c; void main() { b = a; c = a; })";
5200     constexpr char kFS[] = R"(void main(){})";
5201     ANGLE_GL_PROGRAM(program, kVS, kFS);
5202     static const char *varyings[] = {"b", "c"};
5203     glTransformFeedbackVaryings(program, 2, varyings, GL_SEPARATE_ATTRIBS);
5204     glLinkProgram(program);
5205     glUseProgram(program);
5206     ASSERT_GL_NO_ERROR();
5207 
5208     // Bind the transform feedback varyings to non-overlapping regions of the same buffer.
5209     GLBuffer buffer;
5210     glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer, 0, 4);
5211     glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, buffer, 4, 4);
5212     glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 8, nullptr, GL_STATIC_DRAW);
5213     ASSERT_GL_NO_ERROR();
5214     // Two varyings bound to the same buffer should be an error.
5215     glBeginTransformFeedback(GL_POINTS);
5216     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5217 }
5218 
5219 // Check the return type of a given parameter upon getting the active uniforms.
TEST_P(WebGL2CompatibilityTest,UniformVariablesReturnTypes)5220 TEST_P(WebGL2CompatibilityTest, UniformVariablesReturnTypes)
5221 {
5222     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
5223 
5224     std::vector<GLuint> validUniformIndices = {0};
5225     std::vector<GLint> uniformNameLengthBuf(validUniformIndices.size());
5226 
5227     // This should fail because GL_UNIFORM_NAME_LENGTH cannot be used in WebGL2.
5228     glGetActiveUniformsiv(program, static_cast<GLsizei>(validUniformIndices.size()),
5229                           &validUniformIndices[0], GL_UNIFORM_NAME_LENGTH,
5230                           &uniformNameLengthBuf[0]);
5231     EXPECT_GL_ERROR(GL_INVALID_ENUM);
5232 }
5233 
5234 // Tests an error case to ensure we don't crash.
TEST_P(WebGLCompatibilityTest,DrawWithNoProgram)5235 TEST_P(WebGLCompatibilityTest, DrawWithNoProgram)
5236 {
5237     glDrawArrays(GL_TRIANGLES, 0, 6);
5238     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5239 }
5240 
5241 // Ensures that rendering to different texture levels of a sampled texture is supported.
TEST_P(WebGL2CompatibilityTest,RenderToLevelsOfSampledTexture)5242 TEST_P(WebGL2CompatibilityTest, RenderToLevelsOfSampledTexture)
5243 {
5244     // TODO: Fix on Vulkan back-end. http://anglebug.com/4690
5245     ANGLE_SKIP_TEST_IF(IsVulkan());
5246 
5247     constexpr GLsizei kTexSize   = 2;
5248     constexpr GLsizei kTexLevels = 2;
5249 
5250     std::vector<GLColor> texData(kTexSize * kTexSize, GLColor::green);
5251 
5252     GLTexture sourceTexture;
5253     glBindTexture(GL_TEXTURE_2D, sourceTexture);
5254     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5255     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5256     glTexStorage2D(GL_TEXTURE_2D, kTexLevels, GL_RGBA8, kTexSize, kTexSize);
5257     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, GL_RGBA, GL_UNSIGNED_BYTE,
5258                     texData.data());
5259 
5260     GLFramebuffer fbo;
5261     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
5262     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 1);
5263     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
5264     glViewport(0, 0, kTexSize / 2, kTexSize / 2);
5265 
5266     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
5267     ASSERT_GL_NO_ERROR();
5268 
5269     // Should work - drawing from level 0 to level 1.
5270     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5271     EXPECT_GL_NO_ERROR();
5272     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
5273 
5274     // Should not work - drawing from levels [0,1] to level 1.
5275     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
5276     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5277     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
5278 
5279     // Should work - drawing with levels [0,1] to default FBO.
5280     glBindFramebuffer(GL_FRAMEBUFFER, 0);
5281     glViewport(0, 0, getWindowWidth(), getWindowHeight());
5282 
5283     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
5284     EXPECT_GL_NO_ERROR();
5285     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
5286 }
5287 
5288 // Reject attempts to allocate too-large variables in shaders.
5289 // This is an implementation-defined limit - crbug.com/1220237 .
TEST_P(WebGL2CompatibilityTest,ValidateTypeSizes)5290 TEST_P(WebGL2CompatibilityTest, ValidateTypeSizes)
5291 {
5292     constexpr char kFSArrayBlockTooLarge[] = R"(#version 300 es
5293 precision mediump float;
5294 // 1 + the maximum size this implementation allows.
5295 uniform LargeArrayBlock {
5296     vec4 large_array[134217729];
5297 };
5298 
5299 out vec4 out_FragColor;
5300 
5301 void main()
5302 {
5303     if (large_array[1].x == 2.0)
5304         out_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
5305     else
5306         out_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
5307 }
5308 )";
5309 
5310     GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFSArrayBlockTooLarge);
5311     EXPECT_EQ(0u, program);
5312 }
5313 
5314 // Ensure that new type size validation code added for
5315 // crbug.com/1220237 does not crash.
TEST_P(WebGL2CompatibilityTest,ValidatingTypeSizesShouldNotCrash)5316 TEST_P(WebGL2CompatibilityTest, ValidatingTypeSizesShouldNotCrash)
5317 {
5318     constexpr char kFS1[] = R"(#version 300 es
5319 precision mediump float;
5320 out vec4 my_FragColor;
5321 
5322 const vec4 constants[2] = vec4[] (
5323     vec4(0.6, 0.3, 0.0, 3.0),
5324     vec4(-0.6, 0.7, 0.0, -2.0)
5325 );
5326 
5327 void main()
5328 {
5329     my_FragColor = constants[0] + constants[1];
5330     return;
5331 })";
5332 
5333     constexpr char kFS2[] = R"(#version 300 es
5334 precision mediump float;
5335 out vec4 my_FragColor;
5336 
5337 const vec4 constants[2] = vec4[] (
5338     vec4(0.6, 0.3, 0.0, 3.0),
5339     vec4(-0.6, 0.7, 0.0, -2.0)
5340 );
5341 
5342 const vec4 constants2[2] = vec4[] (
5343     constants[1],
5344     constants[0]
5345 );
5346 
5347 void main()
5348 {
5349     my_FragColor = constants2[0] + constants2[1];
5350     return;
5351 })";
5352 
5353     constexpr char kFS3[] = R"(#version 300 es
5354 precision mediump float;
5355 out vec4 my_FragColor;
5356 
5357 const vec4 constants[2] = vec4[] (
5358     vec4(0.6, 0.3, 0.0, 3.0),
5359     vec4(-0.6, 0.7, 0.0, -2.0)
5360 );
5361 
5362 const vec4 constants2[2] = constants;
5363 
5364 void main()
5365 {
5366     my_FragColor = constants2[0] + constants2[1];
5367     return;
5368 })";
5369 
5370     GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFS1);
5371     EXPECT_NE(0u, program);
5372 
5373     program = CompileProgram(essl3_shaders::vs::Simple(), kFS2);
5374     EXPECT_NE(0u, program);
5375 
5376     program = CompileProgram(essl3_shaders::vs::Simple(), kFS3);
5377     EXPECT_NE(0u, program);
5378 }
5379 
5380 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest);
5381 
5382 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2CompatibilityTest);
5383 ANGLE_INSTANTIATE_TEST_ES3(WebGL2CompatibilityTest);
5384 }  // namespace angle
5385