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