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