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