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