blob: b7970286877532d165690db926760bfcd7cdf7c8 [file] [log] [blame]
Geoff Langc287ea62016-09-16 14:46:51 -04001//
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
Geoff Lang677bb6f2017-04-05 12:40:40 -040011#include "common/mathutil.h"
Geoff Langc287ea62016-09-16 14:46:51 -040012#include "test_utils/gl_raii.h"
13
Frank Henigman146e8a12017-03-02 23:22:37 -050014namespace
15{
16
17bool 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
23void 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
Geoff Lang677bb6f2017-04-05 12:40:40 -040036// Extensions that affect the ability to use floating point textures
37constexpr const char *FloatingPointTextureExtensions[] = {
38 "",
39 "GL_EXT_texture_storage",
Geoff Lang677bb6f2017-04-05 12:40:40 -040040 "GL_OES_texture_half_float",
41 "GL_OES_texture_half_float_linear",
42 "GL_EXT_color_buffer_half_float",
Geoff Lang7d4602f2017-09-13 10:45:09 -040043 "GL_OES_texture_float",
44 "GL_OES_texture_float_linear",
Geoff Lang677bb6f2017-04-05 12:40:40 -040045 "GL_EXT_color_buffer_float",
46 "GL_CHROMIUM_color_buffer_float_rgba",
47 "GL_CHROMIUM_color_buffer_float_rgb",
48};
49
Frank Henigman146e8a12017-03-02 23:22:37 -050050} // namespace
51
Geoff Langc287ea62016-09-16 14:46:51 -040052namespace angle
53{
54
55class WebGLCompatibilityTest : public ANGLETest
56{
57 protected:
58 WebGLCompatibilityTest()
59 {
60 setWindowWidth(128);
61 setWindowHeight(128);
62 setConfigRedBits(8);
63 setConfigGreenBits(8);
64 setConfigBlueBits(8);
65 setConfigAlphaBits(8);
66 setWebGLCompatibilityEnabled(true);
67 }
68
69 void SetUp() override
70 {
71 ANGLETest::SetUp();
Geoff Langc339c4e2016-11-29 10:37:36 -050072 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
73 eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -040074 }
75
Geoff Lang677bb6f2017-04-05 12:40:40 -040076 template <typename T>
77 void TestFloatTextureFormat(GLenum internalFormat,
78 GLenum format,
79 GLenum type,
80 bool texturingEnabled,
81 bool linearSamplingEnabled,
82 bool renderingEnabled,
83 const T textureData[4],
84 const float floatData[4])
85 {
86 ASSERT_GL_NO_ERROR();
87
88 const std::string samplingVs =
89 "attribute vec4 position;\n"
90 "varying vec2 texcoord;\n"
91 "void main()\n"
92 "{\n"
93 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
94 " texcoord = (position.xy * 0.5) + 0.5;\n"
95 "}\n";
96
97 const std::string samplingFs =
98 "precision mediump float;\n"
99 "uniform sampler2D tex;\n"
100 "uniform vec4 subtractor;\n"
101 "varying vec2 texcoord;\n"
102 "void main()\n"
103 "{\n"
104 " vec4 color = texture2D(tex, texcoord);\n"
105 " if (abs(color.r - subtractor.r) +\n"
106 " abs(color.g - subtractor.g) +\n"
107 " abs(color.b - subtractor.b) +\n"
108 " abs(color.a - subtractor.a) < 8.0)\n"
109 " {\n"
110 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
111 " }\n"
112 " else\n"
113 " {\n"
114 " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
115 " }\n"
116 "}\n";
117
118 ANGLE_GL_PROGRAM(samplingProgram, samplingVs, samplingFs);
119 glUseProgram(samplingProgram.get());
120
Geoff Langd84a00b2017-10-27 17:27:26 -0400121 // Need RGBA8 renderbuffers for enough precision on the readback
122 if (extensionRequestable("GL_OES_rgb8_rgba8"))
123 {
124 glRequestExtensionANGLE("GL_OES_rgb8_rgba8");
125 }
126 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_rgb8_rgba8") && getClientMajorVersion() < 3);
127 ASSERT_GL_NO_ERROR();
128
Geoff Lang677bb6f2017-04-05 12:40:40 -0400129 GLRenderbuffer rbo;
130 glBindRenderbuffer(GL_RENDERBUFFER, rbo.get());
131 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
132
133 GLFramebuffer fbo;
134 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
135 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo.get());
136
137 GLTexture texture;
138 glBindTexture(GL_TEXTURE_2D, texture.get());
139
140 if (internalFormat == format)
141 {
142 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, textureData);
143 }
144 else
145 {
146 if (getClientMajorVersion() >= 3)
147 {
148 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
149 }
150 else
151 {
152 ASSERT_TRUE(extensionEnabled("GL_EXT_texture_storage"));
153 glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
154 }
155 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, format, type, textureData);
156 }
157
158 if (!texturingEnabled)
159 {
160 // Depending on the entry point and client version, different errors may be generated
161 ASSERT_GLENUM_NE(GL_NO_ERROR, glGetError());
162
163 // Two errors may be generated in the glTexStorage + glTexSubImage case, clear the
164 // second error
165 glGetError();
166
167 return;
168 }
169 ASSERT_GL_NO_ERROR();
170
171 glUniform1i(glGetUniformLocation(samplingProgram.get(), "tex"), 0);
172 glUniform4fv(glGetUniformLocation(samplingProgram.get(), "subtractor"), 1, floatData);
173
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
176 drawQuad(samplingProgram.get(), "position", 0.5f, 1.0f, true);
177 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
178
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
180 drawQuad(samplingProgram.get(), "position", 0.5f, 1.0f, true);
181
182 if (linearSamplingEnabled)
183 {
184 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
185 }
186 else
187 {
188 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
189 }
190
191 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(),
192 0);
193 glBindTexture(GL_TEXTURE_2D, 0);
194 if (!renderingEnabled)
195 {
196 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
197 glCheckFramebufferStatus(GL_FRAMEBUFFER));
198 return;
199 }
200 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
201
202 const std::string renderingVs =
203 "attribute vec4 position;\n"
204 "void main()\n"
205 "{\n"
206 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
207 "}\n";
208
209 const std::string renderingFs =
210 "precision mediump float;\n"
211 "uniform vec4 writeValue;\n"
212 "void main()\n"
213 "{\n"
214 " gl_FragColor = writeValue;\n"
215 "}\n";
216
217 ANGLE_GL_PROGRAM(renderingProgram, renderingVs, renderingFs);
218 glUseProgram(renderingProgram.get());
219
220 glUniform4fv(glGetUniformLocation(renderingProgram.get(), "writeValue"), 1, floatData);
221
222 drawQuad(renderingProgram.get(), "position", 0.5f, 1.0f, true);
223
224 EXPECT_PIXEL_COLOR32F_NEAR(
225 0, 0, GLColor32F(floatData[0], floatData[1], floatData[2], floatData[3]), 1.0f);
226 }
227
Jamie Madillcad97ee2017-02-02 18:52:44 -0500228 // Called from RenderingFeedbackLoopWithDrawBuffersEXT.
229 void drawBuffersEXTFeedbackLoop(GLuint program,
230 const std::array<GLenum, 2> &drawBuffers,
231 GLenum expectedError);
232
Jamie Madill07be8bf2017-02-02 19:59:57 -0500233 // Called from RenderingFeedbackLoopWithDrawBuffers.
234 void drawBuffersFeedbackLoop(GLuint program,
235 const std::array<GLenum, 2> &drawBuffers,
236 GLenum expectedError);
237
Geoff Lang86f81162017-10-30 15:10:45 -0400238 // Called from Enable[Compressed]TextureFormatExtensions
Bryan Bernhart (Intel Americas Inc)2a357412017-09-05 10:42:47 -0700239 void validateTexImageExtensionFormat(GLenum format, const std::string &extName);
Geoff Lang86f81162017-10-30 15:10:45 -0400240 void validateCompressedTexImageExtensionFormat(GLenum format,
241 GLsizei width,
242 GLsizei height,
243 GLsizei blockSize,
244 const std::string &extName,
245 bool subImageAllowed);
Bryan Bernhart (Intel Americas Inc)2a357412017-09-05 10:42:47 -0700246
Geoff Langc339c4e2016-11-29 10:37:36 -0500247 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
Geoff Langc287ea62016-09-16 14:46:51 -0400248};
249
Corentin Wallezfd456442016-12-21 17:57:00 -0500250class WebGL2CompatibilityTest : public WebGLCompatibilityTest
251{
252};
253
Geoff Langc287ea62016-09-16 14:46:51 -0400254// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
255// the GL extension should always be present
256TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
257{
258 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
259}
260
261// Verify that all extension entry points are available
262TEST_P(WebGLCompatibilityTest, EntryPoints)
263{
Geoff Langc339c4e2016-11-29 10:37:36 -0500264 if (extensionEnabled("GL_ANGLE_request_extension"))
Geoff Langc287ea62016-09-16 14:46:51 -0400265 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500266 EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -0400267 }
268}
269
270// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point. Make sure it is usable,
271// even in ES2 contexts.
272TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
273{
274 GLRenderbuffer renderbuffer;
275 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
276 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
277
278 GLFramebuffer framebuffer;
279 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
280 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
281 renderbuffer.get());
282
283 EXPECT_GL_NO_ERROR();
284}
285
286// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
287TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
288{
Geoff Langc339c4e2016-11-29 10:37:36 -0500289 glRequestExtensionANGLE("invalid_extension_string");
Geoff Langc287ea62016-09-16 14:46:51 -0400290 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
291}
292
293// Test enabling the GL_OES_element_index_uint extension
294TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
295{
296 if (getClientMajorVersion() != 2)
297 {
298 // This test only works on ES2 where uint indices are not available by default
299 return;
300 }
301
302 EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
303
304 GLBuffer indexBuffer;
305 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
306
307 GLuint data[] = {0, 1, 2, 1, 3, 2};
308 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
309
310 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
311 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
312 glUseProgram(program.get());
313
Jamie Madille7b96342017-06-23 15:06:08 -0400314 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
Geoff Langc287ea62016-09-16 14:46:51 -0400315 EXPECT_GL_ERROR(GL_INVALID_ENUM);
316
Geoff Langc339c4e2016-11-29 10:37:36 -0500317 if (extensionRequestable("GL_OES_element_index_uint"))
Geoff Langc287ea62016-09-16 14:46:51 -0400318 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500319 glRequestExtensionANGLE("GL_OES_element_index_uint");
Geoff Langc287ea62016-09-16 14:46:51 -0400320 EXPECT_GL_NO_ERROR();
321 EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
322
Jamie Madille7b96342017-06-23 15:06:08 -0400323 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
Geoff Langc287ea62016-09-16 14:46:51 -0400324 EXPECT_GL_NO_ERROR();
325 }
326}
327
Geoff Langff5c63e2017-04-12 15:26:54 -0400328// Test enabling the GL_OES_standard_derivatives extension
329TEST_P(WebGLCompatibilityTest, EnableExtensionStandardDerivitives)
330{
331 EXPECT_FALSE(extensionEnabled("GL_OES_standard_derivatives"));
332
333 const std::string source =
334 "#extension GL_OES_standard_derivatives : require\n"
335 "void main() { gl_FragColor = vec4(dFdx(vec2(1.0, 1.0)).x, 1, 0, 1); }\n";
336 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
337
338 if (extensionRequestable("GL_OES_standard_derivatives"))
339 {
340 glRequestExtensionANGLE("GL_OES_standard_derivatives");
341 EXPECT_GL_NO_ERROR();
342 EXPECT_TRUE(extensionEnabled("GL_OES_standard_derivatives"));
343
344 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
345 ASSERT_NE(0u, shader);
346 glDeleteShader(shader);
347 }
348}
349
350// Test enabling the GL_EXT_shader_texture_lod extension
351TEST_P(WebGLCompatibilityTest, EnableExtensionTextureLOD)
352{
353 EXPECT_FALSE(extensionEnabled("GL_EXT_shader_texture_lod"));
354
355 const std::string source =
356 "#extension GL_EXT_shader_texture_lod : require\n"
357 "uniform sampler2D u_texture;\n"
358 "void main() {\n"
359 " gl_FragColor = texture2DGradEXT(u_texture, vec2(0.0, 0.0), vec2(0.0, 0.0), vec2(0.0, "
360 "0.0));\n"
361 "}\n";
362 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
363
364 if (extensionRequestable("GL_EXT_shader_texture_lod"))
365 {
366 glRequestExtensionANGLE("GL_EXT_shader_texture_lod");
367 EXPECT_GL_NO_ERROR();
368 EXPECT_TRUE(extensionEnabled("GL_EXT_shader_texture_lod"));
369
370 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
371 ASSERT_NE(0u, shader);
372 glDeleteShader(shader);
373 }
374}
375
376// Test enabling the GL_EXT_frag_depth extension
377TEST_P(WebGLCompatibilityTest, EnableExtensionFragDepth)
378{
379 EXPECT_FALSE(extensionEnabled("GL_EXT_frag_depth"));
380
381 const std::string source =
382 "#extension GL_EXT_frag_depth : require\n"
383 "void main() {\n"
384 " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
385 " gl_FragDepthEXT = 1.0;\n"
386 "}\n";
387 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
388
389 if (extensionRequestable("GL_EXT_frag_depth"))
390 {
391 glRequestExtensionANGLE("GL_EXT_frag_depth");
392 EXPECT_GL_NO_ERROR();
393 EXPECT_TRUE(extensionEnabled("GL_EXT_frag_depth"));
394
395 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
396 ASSERT_NE(0u, shader);
397 glDeleteShader(shader);
398 }
399}
400
Geoff Langd7d526a2017-02-21 16:48:43 -0500401// Test enabling the GL_EXT_texture_filter_anisotropic extension
402TEST_P(WebGLCompatibilityTest, EnableExtensionTextureFilterAnisotropic)
403{
404 EXPECT_FALSE(extensionEnabled("GL_EXT_texture_filter_anisotropic"));
405
406 GLfloat maxAnisotropy = 0.0f;
407 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
408 EXPECT_GL_ERROR(GL_INVALID_ENUM);
409
410 GLTexture texture;
411 glBindTexture(GL_TEXTURE_2D, texture.get());
412 ASSERT_GL_NO_ERROR();
413
414 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
415 EXPECT_GL_ERROR(GL_INVALID_ENUM);
416
417 GLfloat currentAnisotropy = 0.0f;
418 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
419 EXPECT_GL_ERROR(GL_INVALID_ENUM);
420
421 if (extensionRequestable("GL_EXT_texture_filter_anisotropic"))
422 {
423 glRequestExtensionANGLE("GL_EXT_texture_filter_anisotropic");
424 EXPECT_GL_NO_ERROR();
425 EXPECT_TRUE(extensionEnabled("GL_EXT_texture_filter_anisotropic"));
426
427 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
428 ASSERT_GL_NO_ERROR();
429 EXPECT_GE(maxAnisotropy, 2.0f);
430
431 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
432 ASSERT_GL_NO_ERROR();
433 EXPECT_EQ(1.0f, currentAnisotropy);
434
435 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f);
436 ASSERT_GL_NO_ERROR();
437 }
438}
439
Bryan Bernhart87c182e2016-11-02 11:23:22 -0700440// Verify that shaders are of a compatible spec when the extension is enabled.
441TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
442{
443 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
444
445 // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
446 const std::string &vert =
447 "struct Foo {\n"
448 " int _webgl_bar;\n"
449 "};\n"
450 "void main()\n"
451 "{\n"
452 " Foo foo = Foo(1);\n"
453 "}";
454
455 // Default fragement shader.
456 const std::string &frag =
457 "void main()\n"
458 "{\n"
459 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n"
460 "}";
461
462 GLuint program = CompileProgram(vert, frag);
463 EXPECT_EQ(0u, program);
464 glDeleteProgram(program);
465}
466
Geoff Lang3fab7632017-09-26 15:45:54 -0400467// Test enabling the GL_NV_pixel_buffer_object extension
468TEST_P(WebGLCompatibilityTest, EnablePixelBufferObjectExtensions)
469{
470 EXPECT_FALSE(extensionEnabled("GL_NV_pixel_buffer_object"));
471 EXPECT_FALSE(extensionEnabled("GL_OES_mapbuffer"));
472 EXPECT_FALSE(extensionEnabled("GL_EXT_map_buffer_range"));
473
474 // These extensions become core in in ES3/WebGL2.
475 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
476
477 GLBuffer buffer;
478 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
479 EXPECT_GL_ERROR(GL_INVALID_ENUM);
480
481 if (extensionRequestable("GL_NV_pixel_buffer_object"))
482 {
483 glRequestExtensionANGLE("GL_NV_pixel_buffer_object");
484 EXPECT_GL_NO_ERROR();
485
486 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
487 EXPECT_GL_NO_ERROR();
488
489 glBufferData(GL_PIXEL_PACK_BUFFER, 4, nullptr, GL_STATIC_DRAW);
490 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
491 EXPECT_GL_NO_ERROR();
492 }
493}
494
495// Test enabling the GL_OES_mapbuffer and GL_EXT_map_buffer_range extensions
496TEST_P(WebGLCompatibilityTest, EnableMapBufferExtensions)
497{
498 EXPECT_FALSE(extensionEnabled("GL_OES_mapbuffer"));
499 EXPECT_FALSE(extensionEnabled("GL_EXT_map_buffer_range"));
500
501 // These extensions become core in in ES3/WebGL2.
502 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
503
504 GLBuffer buffer;
505 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
506 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4, nullptr, GL_STATIC_DRAW);
507
508 glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
509 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
510
511 glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
512 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
513
514 GLint access = 0;
515 glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
516 EXPECT_GL_ERROR(GL_INVALID_ENUM);
517
518 if (extensionRequestable("GL_OES_mapbuffer"))
519 {
520 glRequestExtensionANGLE("GL_OES_mapbuffer");
521 EXPECT_GL_NO_ERROR();
522
523 glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
524 glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
525 glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
526 EXPECT_GL_NO_ERROR();
527 }
528
529 if (extensionRequestable("GL_EXT_map_buffer_range"))
530 {
531 glRequestExtensionANGLE("GL_EXT_map_buffer_range");
532 EXPECT_GL_NO_ERROR();
533
534 glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
535 glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
536 glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
537 EXPECT_GL_NO_ERROR();
538 }
539}
540
Geoff Lang8c7133c2017-09-26 17:31:10 -0400541// Test enabling the GL_OES_fbo_render_mipmap extension
542TEST_P(WebGLCompatibilityTest, EnableRenderMipmapExtension)
543{
544 EXPECT_FALSE(extensionEnabled("GL_OES_fbo_render_mipmap"));
545
546 // This extensions become core in in ES3/WebGL2.
547 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
548
549 GLTexture texture;
550 glBindTexture(GL_TEXTURE_2D, texture);
551 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
552 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
553
554 GLFramebuffer fbo;
555 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
556 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
557 EXPECT_GL_NO_ERROR();
558
559 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
560 EXPECT_GL_ERROR(GL_INVALID_VALUE);
561
562 if (extensionRequestable("GL_OES_fbo_render_mipmap"))
563 {
564 glRequestExtensionANGLE("GL_OES_fbo_render_mipmap");
565 EXPECT_GL_NO_ERROR();
566
567 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
568 EXPECT_GL_NO_ERROR();
569 }
570}
571
Geoff Lang50cac572017-09-26 17:37:43 -0400572// Test enabling the GL_EXT_blend_minmax extension
573TEST_P(WebGLCompatibilityTest, EnableBlendMinMaxExtension)
574{
575 EXPECT_FALSE(extensionEnabled("GL_EXT_blend_minmax"));
576
577 // This extensions become core in in ES3/WebGL2.
578 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
579
580 glBlendEquation(GL_MIN);
581 EXPECT_GL_ERROR(GL_INVALID_ENUM);
582
583 glBlendEquation(GL_MAX);
584 EXPECT_GL_ERROR(GL_INVALID_ENUM);
585
586 if (extensionRequestable("GL_EXT_blend_minmax"))
587 {
588 glRequestExtensionANGLE("GL_EXT_blend_minmax");
589 EXPECT_GL_NO_ERROR();
590
591 glBlendEquation(GL_MIN);
592 glBlendEquation(GL_MAX);
593 EXPECT_GL_NO_ERROR();
594 }
595}
596
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400597// Test enabling the query extensions
598TEST_P(WebGLCompatibilityTest, EnableQueryExtensions)
599{
600 EXPECT_FALSE(extensionEnabled("GL_EXT_occlusion_query_boolean"));
601 EXPECT_FALSE(extensionEnabled("GL_EXT_disjoint_timer_query"));
602 EXPECT_FALSE(extensionEnabled("GL_CHROMIUM_sync_query"));
603
604 // This extensions become core in in ES3/WebGL2.
605 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
606
607 GLQueryEXT badQuery;
608
609 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, badQuery);
610 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
611
612 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, badQuery);
613 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
614
615 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, badQuery);
616 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
617
618 glQueryCounterEXT(GL_TIMESTAMP_EXT, badQuery);
619 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
620
621 glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, badQuery);
622 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
623
624 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
625 {
626 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
627 EXPECT_GL_NO_ERROR();
628
629 GLQueryEXT query;
630 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
631 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
632 EXPECT_GL_NO_ERROR();
633 }
634
635 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
636 {
637 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
638 EXPECT_GL_NO_ERROR();
639
640 GLQueryEXT query1;
641 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query1);
642 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
643 EXPECT_GL_NO_ERROR();
644
645 GLQueryEXT query2;
646 glQueryCounterEXT(query2, GL_TIMESTAMP_EXT);
647 EXPECT_GL_NO_ERROR();
648 }
649
650 if (extensionRequestable("GL_CHROMIUM_sync_query"))
651 {
652 glRequestExtensionANGLE("GL_CHROMIUM_sync_query");
653 EXPECT_GL_NO_ERROR();
654
655 GLQueryEXT query;
656 glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query);
657 glEndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
658 EXPECT_GL_NO_ERROR();
659 }
660}
661
Geoff Lang488130e2017-09-27 13:53:11 -0400662// Test enabling the GL_ANGLE_framebuffer_multisample extension
663TEST_P(WebGLCompatibilityTest, EnableFramebufferMultisampleExtension)
664{
665 EXPECT_FALSE(extensionEnabled("GL_ANGLE_framebuffer_multisample"));
666
667 // This extensions become core in in ES3/WebGL2.
668 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
669
670 GLint maxSamples = 0;
671 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
672 EXPECT_GL_ERROR(GL_INVALID_ENUM);
673
674 GLRenderbuffer renderbuffer;
675 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
676 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 1, GL_RGBA4, 1, 1);
677 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
678
679 if (extensionRequestable("GL_ANGLE_framebuffer_multisample"))
680 {
681 glRequestExtensionANGLE("GL_ANGLE_framebuffer_multisample");
682 EXPECT_GL_NO_ERROR();
683
684 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
685 EXPECT_GL_NO_ERROR();
686
687 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, maxSamples, GL_RGBA4, 1, 1);
688 EXPECT_GL_NO_ERROR();
689 }
690}
691
Geoff Lang63c5a592017-09-27 14:08:16 -0400692// Test enabling the GL_ANGLE_instanced_arrays extension
693TEST_P(WebGLCompatibilityTest, EnableInstancedArraysExtension)
694{
695 EXPECT_FALSE(extensionEnabled("GL_ANGLE_instanced_arrays"));
696
697 // This extensions become core in in ES3/WebGL2.
698 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
699
700 GLint divisor = 0;
701 glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
702 EXPECT_GL_ERROR(GL_INVALID_ENUM);
703
704 glVertexAttribDivisorANGLE(0, 1);
705 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
706
707 if (extensionRequestable("GL_ANGLE_instanced_arrays"))
708 {
709 glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
710 EXPECT_GL_NO_ERROR();
711
712 glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
713 glVertexAttribDivisorANGLE(0, 1);
714 EXPECT_GL_NO_ERROR();
715 }
716}
717
Geoff Lang000dab82017-09-27 14:27:07 -0400718// Test enabling the GL_ANGLE_pack_reverse_row_order extension
719TEST_P(WebGLCompatibilityTest, EnablePackReverseRowOrderExtension)
720{
721 EXPECT_FALSE(extensionEnabled("GL_ANGLE_pack_reverse_row_order"));
722
723 GLint result = 0;
724 glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
725 EXPECT_GL_ERROR(GL_INVALID_ENUM);
726
727 glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
728 EXPECT_GL_ERROR(GL_INVALID_ENUM);
729
730 if (extensionRequestable("GL_ANGLE_pack_reverse_row_order"))
731 {
732 glRequestExtensionANGLE("GL_ANGLE_pack_reverse_row_order");
733 EXPECT_GL_NO_ERROR();
734
735 glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
736 glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
737 EXPECT_GL_NO_ERROR();
738 }
739}
740
741// Test enabling the GL_EXT_unpack_subimage extension
742TEST_P(WebGLCompatibilityTest, EnablePackUnpackSubImageExtension)
743{
744 EXPECT_FALSE(extensionEnabled("GL_EXT_unpack_subimage"));
745
746 // This extensions become core in in ES3/WebGL2.
747 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
748
749 constexpr GLenum parameters[] = {
750 GL_UNPACK_ROW_LENGTH_EXT, GL_UNPACK_SKIP_ROWS_EXT, GL_UNPACK_SKIP_PIXELS_EXT,
751 };
752
753 for (GLenum param : parameters)
754 {
755 GLint resultI = 0;
756 glGetIntegerv(param, &resultI);
757 EXPECT_GL_ERROR(GL_INVALID_ENUM);
758
759 GLfloat resultF = 0.0f;
760 glGetFloatv(param, &resultF);
761 EXPECT_GL_ERROR(GL_INVALID_ENUM);
762
763 glPixelStorei(param, 0);
764 EXPECT_GL_ERROR(GL_INVALID_ENUM);
765 }
766
767 if (extensionRequestable("GL_EXT_unpack_subimage"))
768 {
769 glRequestExtensionANGLE("GL_EXT_unpack_subimage");
770 EXPECT_GL_NO_ERROR();
771
772 for (GLenum param : parameters)
773 {
774 GLint resultI = 0;
775 glGetIntegerv(param, &resultI);
776
777 GLfloat resultF = 0.0f;
778 glGetFloatv(param, &resultF);
779
780 glPixelStorei(param, 0);
781
782 EXPECT_GL_NO_ERROR();
783 }
784 }
785}
786
Geoff Lang4751aab2017-10-30 15:14:52 -0400787TEST_P(WebGLCompatibilityTest, EnableTextureRectangle)
788{
789 EXPECT_FALSE(extensionEnabled("GL_ANGLE_texture_rectangle"));
790
791 GLTexture texture;
792 glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
793 EXPECT_GL_ERROR(GL_INVALID_ENUM);
794
795 GLint minFilter = 0;
796 glGetTexParameteriv(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, &minFilter);
797 EXPECT_GL_ERROR(GL_INVALID_ENUM);
798
799 if (extensionRequestable("GL_ANGLE_texture_rectangle"))
800 {
801 glRequestExtensionANGLE("GL_ANGLE_texture_rectangle");
802 EXPECT_GL_NO_ERROR();
803
804 EXPECT_TRUE(extensionEnabled("GL_ANGLE_texture_rectangle"));
805
806 glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
807 EXPECT_GL_NO_ERROR();
808
809 glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
810 nullptr);
811 EXPECT_GL_NO_ERROR();
812 }
813}
814
Geoff Lang000dab82017-09-27 14:27:07 -0400815// Test enabling the GL_NV_pack_subimage extension
816TEST_P(WebGLCompatibilityTest, EnablePackPackSubImageExtension)
817{
818 EXPECT_FALSE(extensionEnabled("GL_NV_pack_subimage"));
819
820 // This extensions become core in in ES3/WebGL2.
821 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
822
823 constexpr GLenum parameters[] = {
824 GL_PACK_ROW_LENGTH, GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS,
825 };
826
827 for (GLenum param : parameters)
828 {
829 GLint resultI = 0;
830 glGetIntegerv(param, &resultI);
831 EXPECT_GL_ERROR(GL_INVALID_ENUM);
832
833 GLfloat resultF = 0.0f;
834 glGetFloatv(param, &resultF);
835 EXPECT_GL_ERROR(GL_INVALID_ENUM);
836
837 glPixelStorei(param, 0);
838 EXPECT_GL_ERROR(GL_INVALID_ENUM);
839 }
840
841 if (extensionRequestable("GL_NV_pack_subimage"))
842 {
843 glRequestExtensionANGLE("GL_NV_pack_subimage");
844 EXPECT_GL_NO_ERROR();
845
846 for (GLenum param : parameters)
847 {
848 GLint resultI = 0;
849 glGetIntegerv(param, &resultI);
850
851 GLfloat resultF = 0.0f;
852 glGetFloatv(param, &resultF);
853
854 glPixelStorei(param, 0);
855
856 EXPECT_GL_NO_ERROR();
857 }
858 }
859}
860
Geoff Langd84a00b2017-10-27 17:27:26 -0400861TEST_P(WebGLCompatibilityTest, EnableRGB8RGBA8Extension)
862{
863 EXPECT_FALSE(extensionEnabled("GL_OES_rgb8_rgba8"));
864
865 // This extensions become core in in ES3/WebGL2.
866 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
867
868 GLRenderbuffer renderbuffer;
869 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
870 EXPECT_GL_NO_ERROR();
871
872 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 1, 1);
873 EXPECT_GL_ERROR(GL_INVALID_ENUM);
874
875 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
876 EXPECT_GL_ERROR(GL_INVALID_ENUM);
877
878 if (extensionRequestable("GL_OES_rgb8_rgba8"))
879 {
880 glRequestExtensionANGLE("GL_OES_rgb8_rgba8");
881 EXPECT_GL_NO_ERROR();
882
883 EXPECT_TRUE(extensionEnabled("GL_OES_rgb8_rgba8"));
884
885 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, 1, 1);
886 EXPECT_GL_NO_ERROR();
887
888 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
889 EXPECT_GL_NO_ERROR();
890 }
891}
892
Geoff Lange8afa902017-09-27 15:00:43 -0400893// Test enabling the GL_ANGLE_framebuffer_blit extension
894TEST_P(WebGLCompatibilityTest, EnableFramebufferBlitExtension)
895{
896 EXPECT_FALSE(extensionEnabled("GL_ANGLE_framebuffer_blit"));
897
898 // This extensions become core in in ES3/WebGL2.
899 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
900
901 GLFramebuffer fbo;
902
903 glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
904 EXPECT_GL_ERROR(GL_INVALID_ENUM);
905
906 GLint result;
907 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_ANGLE, &result);
908 EXPECT_GL_ERROR(GL_INVALID_ENUM);
909
910 glBlitFramebufferANGLE(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
911 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
912
913 if (extensionRequestable("GL_ANGLE_framebuffer_blit"))
914 {
915 glRequestExtensionANGLE("GL_ANGLE_framebuffer_blit");
916 EXPECT_GL_NO_ERROR();
917
918 glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fbo);
919 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_ANGLE, &result);
920 EXPECT_GL_NO_ERROR();
921 }
922}
923
Geoff Lang2348e212017-09-27 17:46:25 -0400924// Test enabling the GL_OES_get_program_binary extension
925TEST_P(WebGLCompatibilityTest, EnableProgramBinaryExtension)
926{
927 EXPECT_FALSE(extensionEnabled("GL_OES_get_program_binary"));
928
929 // This extensions become core in in ES3/WebGL2.
930 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
931
932 GLint result = 0;
933 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &result);
934 EXPECT_GL_ERROR(GL_INVALID_ENUM);
935
936 glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &result);
937 EXPECT_GL_ERROR(GL_INVALID_ENUM);
938
939 const std::string &vert =
940 "void main()\n"
941 "{\n"
942 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
943 "}\n";
944 const std::string &frag =
945 "precision highp float;\n"
946 "void main()\n"
947 "{\n"
948 " gl_FragColor = vec4(1.0);\n"
949 "}\n";
950 ANGLE_GL_PROGRAM(program, vert, frag);
951
952 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &result);
953 EXPECT_GL_ERROR(GL_INVALID_ENUM);
954
955 uint8_t tempArray[512];
956 GLenum tempFormat = 0;
957 GLsizei tempLength = 0;
958 glGetProgramBinaryOES(program, static_cast<GLsizei>(ArraySize(tempArray)), &tempLength,
959 &tempFormat, tempArray);
960 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
961
962 if (extensionRequestable("GL_OES_get_program_binary"))
963 {
964 glRequestExtensionANGLE("GL_OES_get_program_binary");
965 EXPECT_GL_NO_ERROR();
966
967 glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &result);
968 glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &result);
969 EXPECT_GL_NO_ERROR();
970
971 GLint binaryLength = 0;
972 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
973 EXPECT_GL_NO_ERROR();
974
975 GLenum binaryFormat;
976 GLsizei writeLength = 0;
977 std::vector<uint8_t> binary(binaryLength);
978 glGetProgramBinaryOES(program, binaryLength, &writeLength, &binaryFormat, binary.data());
979 EXPECT_GL_NO_ERROR();
980
981 glProgramBinaryOES(program, binaryFormat, binary.data(), binaryLength);
982 EXPECT_GL_NO_ERROR();
983 }
984}
985
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400986// Verify that the context generates the correct error when the framebuffer attachments are
987// different sizes
Corentin Wallezc3bc9842017-10-11 15:15:59 -0400988TEST_P(WebGLCompatibilityTest, FramebufferAttachmentSizeMismatch)
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400989{
990 GLFramebuffer fbo;
991 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
992
993 GLTexture textures[2];
994 glBindTexture(GL_TEXTURE_2D, textures[0]);
995 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
996 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
997
998 ASSERT_GL_NO_ERROR();
999 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1000
1001 GLRenderbuffer renderbuffer;
1002 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1003 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 3, 3);
1004 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
1005
1006 ASSERT_GL_NO_ERROR();
1007 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1008 glCheckFramebufferStatus(GL_FRAMEBUFFER));
1009
1010 if (extensionRequestable("GL_EXT_draw_buffers"))
1011 {
1012 glRequestExtensionANGLE("GL_EXT_draw_buffers");
1013 EXPECT_GL_NO_ERROR();
1014 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
1015
1016 glBindTexture(GL_TEXTURE_2D, textures[1]);
1017 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1018 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
1019 ASSERT_GL_NO_ERROR();
1020
1021 ASSERT_GL_NO_ERROR();
1022 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1023 glCheckFramebufferStatus(GL_FRAMEBUFFER));
1024
1025 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
1026
1027 ASSERT_GL_NO_ERROR();
1028 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1029
1030 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1031
1032 ASSERT_GL_NO_ERROR();
1033 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
1034 glCheckFramebufferStatus(GL_FRAMEBUFFER));
1035 }
1036}
1037
Corentin Wallez327411e2016-12-09 11:09:17 -05001038// Test that client-side array buffers are forbidden in WebGL mode
1039TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
1040{
1041 const std::string &vert =
1042 "attribute vec3 a_pos;\n"
1043 "void main()\n"
1044 "{\n"
1045 " gl_Position = vec4(a_pos, 1.0);\n"
1046 "}\n";
1047
1048 const std::string &frag =
1049 "precision highp float;\n"
1050 "void main()\n"
1051 "{\n"
1052 " gl_FragColor = vec4(1.0);\n"
1053 "}\n";
1054
1055 ANGLE_GL_PROGRAM(program, vert, frag);
1056
1057 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1058 ASSERT_NE(-1, posLocation);
1059 glUseProgram(program.get());
1060
1061 const auto &vertices = GetQuadVertices();
Corentin Wallezfd456442016-12-21 17:57:00 -05001062 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
Corentin Wallez327411e2016-12-09 11:09:17 -05001063 glEnableVertexAttribArray(posLocation);
1064
1065 ASSERT_GL_NO_ERROR();
1066 glDrawArrays(GL_TRIANGLES, 0, 6);
1067 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1068}
1069
1070// Test that client-side element array buffers are forbidden in WebGL mode
1071TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
1072{
1073 const std::string &vert =
1074 "attribute vec3 a_pos;\n"
1075 "void main()\n"
1076 "{\n"
1077 " gl_Position = vec4(a_pos, 1.0);\n"
1078 "}\n";
1079
1080 const std::string &frag =
1081 "precision highp float;\n"
1082 "void main()\n"
1083 "{\n"
1084 " gl_FragColor = vec4(1.0);\n"
1085 "}\n";
1086
1087 ANGLE_GL_PROGRAM(program, vert, frag);
1088
1089 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1090 ASSERT_NE(-1, posLocation);
1091 glUseProgram(program.get());
1092
1093 const auto &vertices = GetQuadVertices();
1094
1095 GLBuffer vertexBuffer;
1096 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1097 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1098 GL_STATIC_DRAW);
1099
1100 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1101 glEnableVertexAttribArray(posLocation);
1102
Corentin Wallez327411e2016-12-09 11:09:17 -05001103 ASSERT_GL_NO_ERROR();
Corentin Wallezded1b5a2017-03-09 18:58:48 -05001104
1105 // Use the pointer with value of 1 for indices instead of an actual pointer because WebGL also
1106 // enforces that the top bit of indices must be 0 (i.e. offset >= 0) and would generate
1107 // GL_INVALID_VALUE in that case. Using a null pointer gets caught by another check.
1108 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void*>(intptr_t(1)));
Corentin Wallez327411e2016-12-09 11:09:17 -05001109 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1110}
1111
Corentin Wallez672f7f32017-06-15 17:42:17 -04001112// Test that client-side array buffers are forbidden even if the program doesn't use the attribute
1113TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBufferEvenNotUsedOnes)
1114{
1115 const std::string &vert =
1116 "void main()\n"
1117 "{\n"
1118 " gl_Position = vec4(1.0);\n"
1119 "}\n";
1120
1121 const std::string &frag =
1122 "precision highp float;\n"
1123 "void main()\n"
1124 "{\n"
1125 " gl_FragColor = vec4(1.0);\n"
1126 "}\n";
1127
1128 ANGLE_GL_PROGRAM(program, vert, frag);
1129
1130 glUseProgram(program.get());
1131
1132 const auto &vertices = GetQuadVertices();
1133 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
1134 glEnableVertexAttribArray(0);
1135
1136 ASSERT_GL_NO_ERROR();
1137 glDrawArrays(GL_TRIANGLES, 0, 6);
1138 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1139}
1140
Geoff Langfb052642017-10-24 13:42:09 -04001141// Test that passing a null pixel data pointer to TexSubImage calls generates an INVALID_VALUE error
1142TEST_P(WebGLCompatibilityTest, NullPixelDataForSubImage)
1143{
1144 // glTexSubImage2D
1145 {
1146 GLTexture texture;
1147 glBindTexture(GL_TEXTURE_2D, texture);
1148
1149 // TexImage with null data - OK
1150 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1151 EXPECT_GL_NO_ERROR();
1152
1153 // TexSubImage with zero size and null data - OK
1154 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1155 EXPECT_GL_NO_ERROR();
1156
1157 // TexSubImage with non-zero size and null data - Invalid value
1158 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1159 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1160 }
1161
1162 // glTexSubImage3D
1163 if (getClientMajorVersion() >= 3)
1164 {
1165 GLTexture texture;
1166 glBindTexture(GL_TEXTURE_3D, texture);
1167
1168 // TexImage with null data - OK
1169 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1170 EXPECT_GL_NO_ERROR();
1171
1172 // TexSubImage with zero size and null data - OK
1173 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1174 EXPECT_GL_NO_ERROR();
1175
1176 // TexSubImage with non-zero size and null data - Invalid value
1177 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1178 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1179 }
1180}
1181
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05001182// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
1183TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
1184{
1185 // Run the test in an FBO to make sure we have some stencil bits.
1186 GLRenderbuffer renderbuffer;
1187 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
1188 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
1189
1190 GLFramebuffer framebuffer;
1191 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1192 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1193 renderbuffer.get());
1194
1195 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
1196 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
1197 glUseProgram(program.get());
1198 ASSERT_GL_NO_ERROR();
1199
1200 // Having ref and mask the same for front and back is valid.
1201 glStencilMask(255);
1202 glStencilFunc(GL_ALWAYS, 0, 255);
1203 glDrawArrays(GL_TRIANGLES, 0, 6);
1204 ASSERT_GL_NO_ERROR();
1205
1206 // Having a different front - back write mask generates an error.
1207 glStencilMaskSeparate(GL_FRONT, 1);
1208 glDrawArrays(GL_TRIANGLES, 0, 6);
1209 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1210
1211 // Setting both write masks separately to the same value is valid.
1212 glStencilMaskSeparate(GL_BACK, 1);
1213 glDrawArrays(GL_TRIANGLES, 0, 6);
1214 ASSERT_GL_NO_ERROR();
1215
1216 // Having a different stencil front - back mask generates an error
1217 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
1218 glDrawArrays(GL_TRIANGLES, 0, 6);
1219 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1220
1221 // Setting both masks separately to the same value is valid.
1222 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
1223 glDrawArrays(GL_TRIANGLES, 0, 6);
1224 ASSERT_GL_NO_ERROR();
1225
1226 // Having a different stencil front - back reference generates an error
1227 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
1228 glDrawArrays(GL_TRIANGLES, 0, 6);
1229 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1230
1231 // Setting both references separately to the same value is valid.
1232 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
1233 glDrawArrays(GL_TRIANGLES, 0, 6);
1234 ASSERT_GL_NO_ERROR();
1235
1236 // Using different stencil funcs, everything being equal is valid.
1237 glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
1238 glDrawArrays(GL_TRIANGLES, 0, 6);
1239 ASSERT_GL_NO_ERROR();
1240}
1241
Corentin Wallez506fc9c2016-12-21 16:53:33 -05001242// Test that GL_FIXED is forbidden
1243TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
1244{
1245 GLBuffer buffer;
1246 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1247 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1248
1249 glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1250 ASSERT_GL_NO_ERROR();
1251
1252 glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
1253 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1254}
1255
1256// Test the WebGL limit of 255 for the attribute stride
1257TEST_P(WebGLCompatibilityTest, MaxStride)
1258{
1259 GLBuffer buffer;
1260 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1261 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
1262
1263 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
1264 ASSERT_GL_NO_ERROR();
1265
1266 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
1267 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1268}
1269
Corentin Wallezfd456442016-12-21 17:57:00 -05001270// Test the checks for OOB reads in the vertex buffers, non-instanced version
1271TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
1272{
1273 const std::string &vert =
1274 "attribute float a_pos;\n"
1275 "void main()\n"
1276 "{\n"
1277 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1278 "}\n";
1279
1280 const std::string &frag =
1281 "precision highp float;\n"
1282 "void main()\n"
1283 "{\n"
1284 " gl_FragColor = vec4(1.0);\n"
1285 "}\n";
1286
1287 ANGLE_GL_PROGRAM(program, vert, frag);
Corentin Wallezfd456442016-12-21 17:57:00 -05001288 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1289 ASSERT_NE(-1, posLocation);
1290 glUseProgram(program.get());
1291
1292 GLBuffer buffer;
1293 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1294 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1295
1296 glEnableVertexAttribArray(posLocation);
1297
1298 const uint8_t* zeroOffset = nullptr;
1299
1300 // Test touching the last element is valid.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001301 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
Corentin Wallezfd456442016-12-21 17:57:00 -05001302 glDrawArrays(GL_POINTS, 0, 4);
1303 ASSERT_GL_NO_ERROR();
1304
1305 // Test touching the last element + 1 is invalid.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001306 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
Corentin Wallezfd456442016-12-21 17:57:00 -05001307 glDrawArrays(GL_POINTS, 0, 4);
1308 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1309
1310 // Test touching the last element is valid, using a stride.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001311 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
Corentin Wallezfd456442016-12-21 17:57:00 -05001312 glDrawArrays(GL_POINTS, 0, 4);
1313 ASSERT_GL_NO_ERROR();
1314
1315 // Test touching the last element + 1 is invalid, using a stride.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001316 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
Corentin Wallezfd456442016-12-21 17:57:00 -05001317 glDrawArrays(GL_POINTS, 0, 4);
1318 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1319
1320 // Test any offset is valid if no vertices are drawn.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001321 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
Corentin Wallezfd456442016-12-21 17:57:00 -05001322 glDrawArrays(GL_POINTS, 0, 0);
1323 ASSERT_GL_NO_ERROR();
Corentin Wallez91c8de82017-10-12 16:32:44 -04001324
1325 // Test a case of overflow that could give a max vertex that's negative
1326 constexpr GLint kIntMax = std::numeric_limits<GLint>::max();
1327 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 0);
1328 glDrawArrays(GL_POINTS, kIntMax, kIntMax);
1329 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1330}
1331
1332// Test the checks for OOB reads in the vertex buffers, instanced version
1333TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
1334{
1335 const std::string &vert =
1336 "attribute float a_pos;\n"
1337 "attribute float a_w;\n"
1338 "void main()\n"
1339 "{\n"
1340 " gl_Position = vec4(a_pos, a_pos, a_pos, a_w);\n"
1341 "}\n";
1342
1343 const std::string &frag =
1344 "precision highp float;\n"
1345 "void main()\n"
1346 "{\n"
1347 " gl_FragColor = vec4(1.0);\n"
1348 "}\n";
1349
1350 ANGLE_GL_PROGRAM(program, vert, frag);
1351 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1352 GLint wLocation = glGetAttribLocation(program.get(), "a_w");
1353 ASSERT_NE(-1, posLocation);
1354 ASSERT_NE(-1, wLocation);
1355 glUseProgram(program.get());
1356
1357 GLBuffer buffer;
1358 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1359 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1360
1361 glEnableVertexAttribArray(posLocation);
1362 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1363 glVertexAttribDivisor(posLocation, 0);
1364
1365 glEnableVertexAttribArray(wLocation);
1366 glVertexAttribDivisor(wLocation, 1);
1367
1368 const uint8_t* zeroOffset = nullptr;
1369
1370 // Test touching the last element is valid.
1371 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1372 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1373 ASSERT_GL_NO_ERROR();
1374
1375 // Test touching the last element + 1 is invalid.
1376 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1377 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1378 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1379
1380 // Test touching the last element is valid, using a stride.
1381 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1382 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1383 ASSERT_GL_NO_ERROR();
1384
1385 // Test touching the last element + 1 is invalid, using a stride.
1386 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1387 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1388 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1389
1390 // Test any offset is valid if no vertices are drawn.
1391 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1392 glDrawArraysInstanced(GL_POINTS, 0, 0, 1);
1393 ASSERT_GL_NO_ERROR();
1394
1395 // Test any offset is valid if no primitives are drawn.
1396 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1397 glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
1398 ASSERT_GL_NO_ERROR();
1399}
1400
1401// Test the checks for OOB reads in the vertex buffers, ANGLE_instanced_arrays version
1402TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsInstancedANGLE)
1403{
1404 ANGLE_SKIP_TEST_IF(!extensionRequestable("GL_ANGLE_instanced_arrays"));
1405 glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
1406 EXPECT_GL_NO_ERROR();
1407
1408 const std::string &vert =
1409 "attribute float a_pos;\n"
1410 "attribute float a_w;\n"
1411 "void main()\n"
1412 "{\n"
1413 " gl_Position = vec4(a_pos, a_pos, a_pos, a_w);\n"
1414 "}\n";
1415
1416 const std::string &frag =
1417 "precision highp float;\n"
1418 "void main()\n"
1419 "{\n"
1420 " gl_FragColor = vec4(1.0);\n"
1421 "}\n";
1422
1423 ANGLE_GL_PROGRAM(program, vert, frag);
1424 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1425 GLint wLocation = glGetAttribLocation(program.get(), "a_w");
1426 ASSERT_NE(-1, posLocation);
1427 ASSERT_NE(-1, wLocation);
1428 glUseProgram(program.get());
1429
1430 GLBuffer buffer;
1431 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1432 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1433
1434 glEnableVertexAttribArray(posLocation);
1435 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1436 glVertexAttribDivisorANGLE(posLocation, 0);
1437
1438 glEnableVertexAttribArray(wLocation);
1439 glVertexAttribDivisorANGLE(wLocation, 1);
1440
1441 const uint8_t* zeroOffset = nullptr;
1442
1443 // Test touching the last element is valid.
1444 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1445 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1446 ASSERT_GL_NO_ERROR();
1447
1448 // Test touching the last element + 1 is invalid.
1449 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1450 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1451 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1452
1453 // Test touching the last element is valid, using a stride.
1454 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1455 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1456 ASSERT_GL_NO_ERROR();
1457
1458 // Test touching the last element + 1 is invalid, using a stride.
1459 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1460 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1461 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1462
1463 // Test any offset is valid if no vertices are drawn.
1464 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1465 glDrawArraysInstancedANGLE(GL_POINTS, 0, 0, 1);
1466 ASSERT_GL_NO_ERROR();
1467
1468 // Test any offset is valid if no primitives are drawn.
1469 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1470 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 0);
1471 ASSERT_GL_NO_ERROR();
Corentin Wallezfd456442016-12-21 17:57:00 -05001472}
1473
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001474// Test the checks for OOB reads in the index buffer
1475TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
Geoff Lang5f319a42017-01-09 16:49:19 -05001476{
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001477 const std::string &vert =
1478 "attribute float a_pos;\n"
1479 "void main()\n"
1480 "{\n"
1481 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1482 "}\n";
Geoff Lang5f319a42017-01-09 16:49:19 -05001483
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001484 const std::string &frag =
1485 "precision highp float;\n"
1486 "void main()\n"
1487 "{\n"
1488 " gl_FragColor = vec4(1.0);\n"
1489 "}\n";
1490
1491 ANGLE_GL_PROGRAM(program, vert, frag);
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001492 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1493 ASSERT_NE(-1, posLocation);
1494 glUseProgram(program.get());
1495
1496 GLBuffer vertexBuffer;
1497 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1498 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1499
1500 glEnableVertexAttribArray(posLocation);
Corentin Wallez91c8de82017-10-12 16:32:44 -04001501 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001502
1503 const uint8_t *zeroOffset = nullptr;
1504 const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
1505
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001506 GLBuffer indexBuffer;
1507 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1508 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
Geoff Lang5f319a42017-01-09 16:49:19 -05001509 ASSERT_GL_NO_ERROR();
1510
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001511 // Test touching the last index is valid
1512 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
1513 ASSERT_GL_NO_ERROR();
Geoff Lang5f319a42017-01-09 16:49:19 -05001514
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001515 // Test touching the last + 1 element is invalid
1516 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
1517 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang5f319a42017-01-09 16:49:19 -05001518
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001519 // Test any offset if valid if count is zero
1520 glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
1521 ASSERT_GL_NO_ERROR();
Corentin Wallezfe9306a2017-02-01 17:41:05 -05001522
1523 // Test touching the first index is valid
1524 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
1525 ASSERT_GL_NO_ERROR();
1526
1527 // Test touching the first - 1 index is invalid
1528 // The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
1529 // the historic behavior of WebGL implementations
1530 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset - 1);
1531 EXPECT_GL_ERROR(GL_INVALID_VALUE);
Geoff Lang5f319a42017-01-09 16:49:19 -05001532}
1533
Corentin Wallez91c8de82017-10-12 16:32:44 -04001534// Test the checks for OOB in vertex buffers caused by indices, non-instanced version
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001535TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInVertexBuffer)
1536{
1537 const std::string &vert =
1538 "attribute float a_pos;\n"
1539 "void main()\n"
1540 "{\n"
1541 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1542 "}\n";
1543
1544 const std::string &frag =
1545 "precision highp float;\n"
1546 "void main()\n"
1547 "{\n"
1548 " gl_FragColor = vec4(1.0);\n"
1549 "}\n";
1550
1551 ANGLE_GL_PROGRAM(program, vert, frag);
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001552 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1553 ASSERT_NE(-1, posLocation);
1554 glUseProgram(program.get());
1555
1556 GLBuffer vertexBuffer;
1557 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1558 glBufferData(GL_ARRAY_BUFFER, 8, nullptr, GL_STATIC_DRAW);
1559
1560 glEnableVertexAttribArray(posLocation);
Corentin Wallez91c8de82017-10-12 16:32:44 -04001561 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001562
1563 const uint8_t *zeroOffset = nullptr;
1564 const uint8_t testIndices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 255};
1565
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001566 GLBuffer indexBuffer;
1567 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1568 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(testIndices), testIndices, GL_STATIC_DRAW);
1569 ASSERT_GL_NO_ERROR();
1570
1571 // Test touching the end of the vertex buffer is valid
1572 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 7);
1573 ASSERT_GL_NO_ERROR();
1574
1575 // Test touching just after the end of the vertex buffer is invalid
1576 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 8);
1577 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1578
1579 // Test touching the whole vertex buffer is valid
1580 glDrawElements(GL_POINTS, 8, GL_UNSIGNED_BYTE, zeroOffset + 0);
1581 ASSERT_GL_NO_ERROR();
1582
1583 // Test an index that would be negative
1584 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 9);
1585 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1586}
1587
Frank Henigman6137ddc2017-02-10 18:55:07 -05001588// Test depth range with 'near' more or less than 'far.'
1589TEST_P(WebGLCompatibilityTest, DepthRange)
1590{
1591 glDepthRangef(0, 1);
1592 ASSERT_GL_NO_ERROR();
1593
1594 glDepthRangef(.5, .5);
1595 ASSERT_GL_NO_ERROR();
1596
1597 glDepthRangef(1, 0);
1598 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1599}
1600
Frank Henigman146e8a12017-03-02 23:22:37 -05001601// Test all blend function combinations.
1602// In WebGL it is invalid to combine constant color with constant alpha.
1603TEST_P(WebGLCompatibilityTest, BlendWithConstantColor)
1604{
1605 constexpr GLenum srcFunc[] = {
1606 GL_ZERO,
1607 GL_ONE,
1608 GL_SRC_COLOR,
1609 GL_ONE_MINUS_SRC_COLOR,
1610 GL_DST_COLOR,
1611 GL_ONE_MINUS_DST_COLOR,
1612 GL_SRC_ALPHA,
1613 GL_ONE_MINUS_SRC_ALPHA,
1614 GL_DST_ALPHA,
1615 GL_ONE_MINUS_DST_ALPHA,
1616 GL_CONSTANT_COLOR,
1617 GL_ONE_MINUS_CONSTANT_COLOR,
1618 GL_CONSTANT_ALPHA,
1619 GL_ONE_MINUS_CONSTANT_ALPHA,
1620 GL_SRC_ALPHA_SATURATE,
1621 };
1622
1623 constexpr GLenum dstFunc[] = {
1624 GL_ZERO, GL_ONE,
1625 GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
1626 GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
1627 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1628 GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA,
1629 GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
1630 GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA,
1631 };
1632
1633 for (GLenum src : srcFunc)
1634 {
1635 for (GLenum dst : dstFunc)
1636 {
1637 glBlendFunc(src, dst);
1638 CheckBlendFunctions(src, dst);
1639 glBlendFuncSeparate(src, dst, GL_ONE, GL_ONE);
1640 CheckBlendFunctions(src, dst);
1641 }
1642 }
1643}
1644
Geoff Langfc32e8b2017-05-31 14:16:59 -04001645// Test that binding/querying uniforms and attributes with invalid names generates errors
1646TEST_P(WebGLCompatibilityTest, InvalidAttributeAndUniformNames)
1647{
1648 const std::string validAttribName =
1649 "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
1650 const std::string validUniformName =
1651 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
Geoff Langa71a98e2017-06-19 15:15:00 -04001652 std::vector<char> invalidSet = {'"', '$', '`', '@', '\''};
1653 if (getClientMajorVersion() < 3)
1654 {
1655 invalidSet.push_back('\\');
1656 }
Geoff Langfc32e8b2017-05-31 14:16:59 -04001657
1658 std::string vert = "attribute float ";
1659 vert += validAttribName;
1660 vert +=
1661 ";\n"
1662 "void main()\n"
1663 "{\n"
1664 " gl_Position = vec4(1.0);\n"
1665 "}\n";
1666
1667 std::string frag =
1668 "precision highp float;\n"
1669 "uniform vec4 ";
1670 frag += validUniformName;
Geoff Langcab92ee2017-07-19 17:32:07 -04001671 // Insert illegal characters into comments
Geoff Langfc32e8b2017-05-31 14:16:59 -04001672 frag +=
1673 ";\n"
Geoff Langcab92ee2017-07-19 17:32:07 -04001674 " // $ \" @ /*\n"
Geoff Langfc32e8b2017-05-31 14:16:59 -04001675 "void main()\n"
Geoff Langcab92ee2017-07-19 17:32:07 -04001676 "{/*\n"
1677 " ` @ $\n"
1678 " */gl_FragColor = vec4(1.0);\n"
Geoff Langfc32e8b2017-05-31 14:16:59 -04001679 "}\n";
1680
1681 ANGLE_GL_PROGRAM(program, vert, frag);
1682 EXPECT_GL_NO_ERROR();
1683
1684 for (char invalidChar : invalidSet)
1685 {
1686 std::string invalidName = validAttribName + invalidChar;
1687 glGetAttribLocation(program, invalidName.c_str());
1688 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1689 << "glGetAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1690
1691 glBindAttribLocation(program, 0, invalidName.c_str());
1692 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1693 << "glBindAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1694 }
1695
1696 for (char invalidChar : invalidSet)
1697 {
1698 std::string invalidName = validUniformName + invalidChar;
1699 glGetUniformLocation(program, invalidName.c_str());
1700 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1701 << "glGetUniformLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1702 }
1703
1704 for (char invalidChar : invalidSet)
1705 {
1706 std::string invalidAttribName = validAttribName + invalidChar;
1707 const char *invalidVert[] = {
1708 "attribute float ",
1709 invalidAttribName.c_str(),
1710 ";\n",
1711 "void main()\n",
1712 "{\n",
1713 " gl_Position = vec4(1.0);\n",
1714 "}\n",
1715 };
1716
1717 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1718 glShaderSource(shader, static_cast<GLsizei>(ArraySize(invalidVert)), invalidVert, nullptr);
1719 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1720 glDeleteShader(shader);
1721 }
1722}
1723
Geoff Langcab92ee2017-07-19 17:32:07 -04001724// Test that line continuation is handled correctly when valdiating shader source
Bryan Bernhart (Intel Americas Inc)335d8bf2017-10-23 15:41:43 -07001725TEST_P(WebGLCompatibilityTest, ShaderSourceLineContinuation)
1726{
1727 // Verify that a line continuation character (i.e. backslash) cannot be used
1728 // within a preprocessor directive in a ES2 context.
1729 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1730
1731 const char *validVert =
1732 "#define foo this is a test\n"
1733 "precision mediump float;\n"
1734 "void main()\n"
1735 "{\n"
1736 " gl_Position = vec4(1.0);\n"
1737 "}\n";
1738
1739 const char *invalidVert =
1740 "#define foo this \\n"
1741 " is a test\n"
1742 "precision mediump float;\n"
1743 "void main()\n"
1744 "{\n"
1745 " gl_Position = vec4(1.0);\n"
1746 "}\n";
1747
1748 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1749 glShaderSource(shader, 1, &validVert, nullptr);
1750 EXPECT_GL_NO_ERROR();
1751
1752 glShaderSource(shader, 1, &invalidVert, nullptr);
1753 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1754 glDeleteShader(shader);
1755}
1756
1757// Test that line continuation is handled correctly when valdiating shader source
Geoff Langcab92ee2017-07-19 17:32:07 -04001758TEST_P(WebGL2CompatibilityTest, ShaderSourceLineContinuation)
1759{
1760 const char *validVert =
1761 "#version 300 es\n"
1762 "precision mediump float;\n"
1763 "\n"
1764 "void main ()\n"
1765 "{\n"
1766 " float f\\\n"
1767 "oo = 1.0;\n"
1768 " gl_Position = vec4(foo);\n"
1769 "}\n";
1770
1771 const char *invalidVert =
1772 "#version 300 es\n"
1773 "precision mediump float;\n"
1774 "\n"
1775 "void main ()\n"
1776 "{\n"
1777 " float f\\$\n"
1778 "oo = 1.0;\n"
1779 " gl_Position = vec4(foo);\n"
1780 "}\n";
1781
1782 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1783 glShaderSource(shader, 1, &validVert, nullptr);
1784 EXPECT_GL_NO_ERROR();
1785 glShaderSource(shader, 1, &invalidVert, nullptr);
1786 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1787 glDeleteShader(shader);
1788}
1789
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001790// Tests bindAttribLocations for reserved prefixes and length limits
1791TEST_P(WebGLCompatibilityTest, BindAttribLocationLimitation)
1792{
1793 constexpr int maxLocStringLength = 256;
1794 const std::string tooLongString(maxLocStringLength + 1, '_');
1795
1796 glBindAttribLocation(0, 0, "_webgl_var");
1797
1798 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1799
1800 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
1801
1802 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1803}
1804
Corentin Wallez0dc97812017-06-22 14:38:44 -04001805// Test that having no attributes with a zero divisor is valid in WebGL2
Geoff Lang407d4e72017-04-12 14:54:11 -04001806TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
1807{
1808 const std::string &vert =
1809 "attribute float a_pos;\n"
1810 "void main()\n"
1811 "{\n"
1812 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1813 "}\n";
1814
1815 const std::string &frag =
1816 "precision highp float;\n"
1817 "void main()\n"
1818 "{\n"
1819 " gl_FragColor = vec4(1.0);\n"
1820 "}\n";
1821
1822 ANGLE_GL_PROGRAM(program, vert, frag);
1823
1824 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1825 ASSERT_NE(-1, posLocation);
1826
1827 glUseProgram(program.get());
1828
1829 GLBuffer buffer;
1830 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1831 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1832
1833 glEnableVertexAttribArray(posLocation);
1834 glVertexAttribDivisor(posLocation, 1);
1835
Geoff Lang407d4e72017-04-12 14:54:11 -04001836 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1837 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
Geoff Lang407d4e72017-04-12 14:54:11 -04001838 ASSERT_GL_NO_ERROR();
1839}
1840
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001841// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
1842TEST_P(WebGLCompatibilityTest, NPOT)
1843{
1844 EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
1845
1846 // Create a texture and set an NPOT mip 0, should always be acceptable.
1847 GLTexture texture;
1848 glBindTexture(GL_TEXTURE_2D, texture.get());
1849 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1850 ASSERT_GL_NO_ERROR();
1851
1852 // Try setting an NPOT mip 1 and verify the error if WebGL 1
1853 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1854 if (getClientMajorVersion() < 3)
1855 {
1856 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1857 }
1858 else
1859 {
1860 ASSERT_GL_NO_ERROR();
1861 }
1862
1863 if (extensionRequestable("GL_OES_texture_npot"))
1864 {
1865 glRequestExtensionANGLE("GL_OES_texture_npot");
1866 ASSERT_GL_NO_ERROR();
1867
1868 // Try again to set NPOT mip 1
1869 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1870 ASSERT_GL_NO_ERROR();
1871 }
1872}
1873
Jamie Madillcad97ee2017-02-02 18:52:44 -05001874template <typename T>
1875void FillTexture2D(GLuint texture,
1876 GLsizei width,
1877 GLsizei height,
1878 const T &onePixelData,
1879 GLint level,
1880 GLint internalFormat,
1881 GLenum format,
1882 GLenum type)
1883{
1884 std::vector<T> allPixelsData(width * height, onePixelData);
1885
1886 glBindTexture(GL_TEXTURE_2D, texture);
1887 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
1888 allPixelsData.data());
1889 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1890 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1891 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1892 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1893}
1894
Frank Henigman875bbba2017-02-08 16:38:17 -05001895// Test that unset gl_Position defaults to (0,0,0,0).
1896TEST_P(WebGLCompatibilityTest, DefaultPosition)
1897{
1898 // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
1899 // and green otherwise. The center of each quadrant will be red if and only if all
1900 // four corners are red.
1901 const std::string vertexShader =
1902 "attribute vec3 pos;\n"
1903 "varying vec4 color;\n"
1904 "void main() {\n"
1905 " if (gl_Position == vec4(0,0,0,0)) {\n"
1906 " color = vec4(1,0,0,1);\n"
1907 " } else {\n"
1908 " color = vec4(0,1,0,1);\n"
1909 " }\n"
1910 " gl_Position = vec4(pos,1);\n"
1911 "}\n";
1912
1913 const std::string fragmentShader =
1914 "precision mediump float;\n"
1915 "varying vec4 color;\n"
1916 "void main() {\n"
1917 " gl_FragColor = color;\n"
1918 "}\n";
1919
1920 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1921 drawQuad(program.get(), "pos", 0.0f, 1.0f, true);
1922 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1923 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1924 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1925 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1926}
1927
Jamie Madilla4595b82017-01-11 17:36:34 -05001928// Tests that a rendering feedback loop triggers a GL error under WebGL.
1929// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
1930TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
1931{
1932 const std::string vertexShader =
1933 "attribute vec4 a_position;\n"
1934 "varying vec2 v_texCoord;\n"
1935 "void main() {\n"
1936 " gl_Position = a_position;\n"
1937 " v_texCoord = (a_position.xy * 0.5) + 0.5;\n"
1938 "}\n";
1939
1940 const std::string fragmentShader =
1941 "precision mediump float;\n"
1942 "varying vec2 v_texCoord;\n"
1943 "uniform sampler2D u_texture;\n"
1944 "void main() {\n"
1945 " // Shader swizzles color channels so we can tell if the draw succeeded.\n"
1946 " gl_FragColor = texture2D(u_texture, v_texCoord).gbra;\n"
1947 "}\n";
1948
1949 GLTexture texture;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001950 FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001951
1952 ASSERT_GL_NO_ERROR();
1953
1954 GLFramebuffer framebuffer;
1955 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1956 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1957
1958 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1959
1960 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1961
1962 GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
1963 ASSERT_NE(-1, uniformLoc);
1964
1965 glUseProgram(program.get());
1966 glUniform1i(uniformLoc, 0);
1967 glDisable(GL_BLEND);
1968 glDisable(GL_DEPTH_TEST);
1969 ASSERT_GL_NO_ERROR();
1970
1971 // Drawing with a texture that is also bound to the current framebuffer should fail
1972 glBindTexture(GL_TEXTURE_2D, texture.get());
1973 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1974 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1975
1976 // Ensure that the texture contents did not change after the previous render
1977 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1978 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1979 ASSERT_GL_NO_ERROR();
1980 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1981
1982 // Drawing when texture is bound to an inactive uniform should succeed
1983 GLTexture texture2;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001984 FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001985
1986 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1987 glActiveTexture(GL_TEXTURE1);
1988 glBindTexture(GL_TEXTURE_2D, texture.get());
1989 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1990 ASSERT_GL_NO_ERROR();
1991 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1992}
1993
Bryan Bernhart58806562017-01-05 13:09:31 -08001994// Test for the max draw buffers and color attachments.
1995TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
1996{
1997 // This test only applies to ES2.
1998 if (getClientMajorVersion() != 2)
1999 {
2000 return;
2001 }
2002
2003 GLFramebuffer fbo[2];
2004 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
2005
2006 // Test that is valid when we bind with a single attachment point.
2007 GLTexture texture;
2008 glBindTexture(GL_TEXTURE_2D, texture.get());
2009 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2010 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2011 ASSERT_GL_NO_ERROR();
2012
2013 // Test that enabling the draw buffers extension will allow us to bind with a non-zero
2014 // attachment point.
2015 if (extensionRequestable("GL_EXT_draw_buffers"))
2016 {
2017 glRequestExtensionANGLE("GL_EXT_draw_buffers");
2018 EXPECT_GL_NO_ERROR();
2019 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
2020
2021 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
2022
2023 GLTexture texture2;
2024 glBindTexture(GL_TEXTURE_2D, texture2.get());
2025 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2026 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
2027 0);
2028 ASSERT_GL_NO_ERROR();
2029 }
2030}
2031
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002032// Test that the offset in the index buffer is forced to be a multiple of the element size
2033TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
2034{
2035 const std::string &vert =
2036 "attribute vec3 a_pos;\n"
2037 "void main()\n"
2038 "{\n"
2039 " gl_Position = vec4(a_pos, 1.0);\n"
2040 "}\n";
2041
2042 const std::string &frag =
2043 "precision highp float;\n"
2044 "void main()\n"
2045 "{\n"
2046 " gl_FragColor = vec4(1.0);\n"
2047 "}\n";
2048
2049 ANGLE_GL_PROGRAM(program, vert, frag);
2050
2051 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
2052 ASSERT_NE(-1, posLocation);
2053 glUseProgram(program.get());
2054
2055 const auto &vertices = GetQuadVertices();
2056
2057 GLBuffer vertexBuffer;
2058 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
2059 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
2060 GL_STATIC_DRAW);
2061
2062 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
2063 glEnableVertexAttribArray(posLocation);
2064
2065 GLBuffer indexBuffer;
Brandon Jonesed5b46f2017-07-21 08:39:17 -07002066 const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0, 0};
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002067 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
2068 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
2069
2070 ASSERT_GL_NO_ERROR();
2071
2072 const char *zeroIndices = nullptr;
2073
2074 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
2075 ASSERT_GL_NO_ERROR();
2076
Brandon Jonesed5b46f2017-07-21 08:39:17 -07002077 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002078 ASSERT_GL_NO_ERROR();
2079
Brandon Jonesed5b46f2017-07-21 08:39:17 -07002080 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices + 1);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002081 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2082}
2083
2084// Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
2085// size
2086TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
2087{
2088 const char *zeroOffset = nullptr;
2089
2090 // Base case, vector of two floats
2091 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
2092 ASSERT_GL_NO_ERROR();
2093
2094 // Test setting a non-multiple offset
2095 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
2096 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2097 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
2098 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2099 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
2100 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2101
2102 // Test setting a non-multiple stride
2103 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
2104 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2105 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
2106 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2107 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
2108 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2109}
2110
Jamie Madillcad97ee2017-02-02 18:52:44 -05002111void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
2112 const std::array<GLenum, 2> &drawBuffers,
2113 GLenum expectedError)
2114{
2115 glDrawBuffersEXT(2, drawBuffers.data());
2116
2117 // Make sure framebuffer is complete before feedback loop detection
2118 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2119
2120 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2121
2122 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2123 // it should be NO_ERROR"
2124 EXPECT_GL_ERROR(expectedError);
2125}
2126
2127// This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
2128// Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
2129TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
2130{
2131 const std::string vertexShader =
2132 "attribute vec4 aPosition;\n"
2133 "varying vec2 texCoord;\n"
2134 "void main() {\n"
2135 " gl_Position = aPosition;\n"
2136 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2137 "}\n";
2138
2139 const std::string fragmentShader =
2140 "#extension GL_EXT_draw_buffers : require\n"
2141 "precision mediump float;\n"
2142 "uniform sampler2D tex;\n"
2143 "varying vec2 texCoord;\n"
2144 "void main() {\n"
2145 " gl_FragData[0] = texture2D(tex, texCoord);\n"
2146 " gl_FragData[1] = texture2D(tex, texCoord);\n"
2147 "}\n";
2148
2149 GLsizei width = 8;
2150 GLsizei height = 8;
2151
2152 // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
2153 // extension and gl_FragData semantics are changed to enforce indexing by zero always.
2154 // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
2155 if (/*!extensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
2156 {
2157 // No WEBGL_draw_buffers support -- this is legal.
2158 return;
2159 }
2160
2161 GLint maxDrawBuffers = 0;
2162 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2163
Yunchao He9550c602018-02-13 14:47:05 +08002164 // Test skipped because MAX_DRAW_BUFFERS is too small.
2165 ANGLE_SKIP_TEST_IF(maxDrawBuffers < 2);
Jamie Madillcad97ee2017-02-02 18:52:44 -05002166
2167 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2168 glUseProgram(program.get());
2169 glViewport(0, 0, width, height);
2170
2171 GLTexture tex0;
2172 GLTexture tex1;
2173 GLFramebuffer fbo;
2174 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2175 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2176 ASSERT_GL_NO_ERROR();
2177
2178 glBindTexture(GL_TEXTURE_2D, tex1.get());
2179 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2180 ASSERT_NE(-1, texLoc);
2181 glUniform1i(texLoc, 0);
2182 ASSERT_GL_NO_ERROR();
2183
2184 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2185 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2186 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2187 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
2188
2189 drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
2190 GL_INVALID_OPERATION);
2191 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2192 GL_INVALID_OPERATION);
2193 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
2194}
2195
Jamie Madill07be8bf2017-02-02 19:59:57 -05002196// Test tests that texture copying feedback loops are properly rejected in WebGL.
2197// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
2198TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
2199{
2200 GLTexture texture;
2201 glBindTexture(GL_TEXTURE_2D, texture.get());
2202 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2204 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2207
2208 GLTexture texture2;
2209 glBindTexture(GL_TEXTURE_2D, texture2.get());
2210 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2215
2216 GLFramebuffer framebuffer;
2217 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2218 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2219
2220 // framebuffer should be FRAMEBUFFER_COMPLETE.
2221 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2222 ASSERT_GL_NO_ERROR();
2223
2224 // testing copyTexImage2D
2225
2226 // copyTexImage2D to same texture but different level
2227 glBindTexture(GL_TEXTURE_2D, texture.get());
2228 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
2229 EXPECT_GL_NO_ERROR();
2230
2231 // copyTexImage2D to same texture same level, invalid feedback loop
2232 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2233 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2234
2235 // copyTexImage2D to different texture
2236 glBindTexture(GL_TEXTURE_2D, texture2.get());
2237 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2238 EXPECT_GL_NO_ERROR();
2239
2240 // testing copyTexSubImage2D
2241
2242 // copyTexSubImage2D to same texture but different level
2243 glBindTexture(GL_TEXTURE_2D, texture.get());
2244 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
2245 EXPECT_GL_NO_ERROR();
2246
2247 // copyTexSubImage2D to same texture same level, invalid feedback loop
2248 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2249 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2250
2251 // copyTexSubImage2D to different texture
2252 glBindTexture(GL_TEXTURE_2D, texture2.get());
2253 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2254 EXPECT_GL_NO_ERROR();
2255}
2256
2257void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
2258 const std::array<GLenum, 2> &drawBuffers,
2259 GLenum expectedError)
2260{
2261 glDrawBuffers(2, drawBuffers.data());
2262
2263 // Make sure framebuffer is complete before feedback loop detection
2264 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2265
2266 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2267
2268 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2269 // it should be NO_ERROR"
2270 EXPECT_GL_ERROR(expectedError);
2271}
2272
Yuly Novikov817232e2017-02-22 18:36:10 -05002273// Tests invariance matching rules between built in varyings.
2274// Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
2275TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
2276{
2277 const std::string vertexShaderVariant =
2278 "varying vec4 v_varying;\n"
2279 "void main()\n"
2280 "{\n"
2281 " gl_PointSize = 1.0;\n"
2282 " gl_Position = v_varying;\n"
2283 "}";
2284 const std::string fragmentShaderInvariantGlFragCoord =
2285 "invariant gl_FragCoord;\n"
2286 "void main()\n"
2287 "{\n"
2288 " gl_FragColor = gl_FragCoord;\n"
2289 "}";
2290 const std::string fragmentShaderInvariantGlPointCoord =
2291 "invariant gl_PointCoord;\n"
2292 "void main()\n"
2293 "{\n"
2294 " gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);\n"
2295 "}";
2296
2297 GLuint program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlFragCoord);
2298 EXPECT_EQ(0u, program);
2299
2300 program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlPointCoord);
2301 EXPECT_EQ(0u, program);
2302}
2303
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002304// Tests global namespace conflicts between uniforms and attributes.
2305// Based on WebGL test conformance/glsl/misc/shaders-with-name-conflicts.html.
2306TEST_P(WebGLCompatibilityTest, GlobalNamesConflict)
2307{
2308 const std::string vertexShader =
2309 "attribute vec4 foo;\n"
2310 "void main()\n"
2311 "{\n"
2312 " gl_Position = foo;\n"
2313 "}";
2314 const std::string fragmentShader =
2315 "precision mediump float;\n"
2316 "uniform vec4 foo;\n"
2317 "void main()\n"
2318 "{\n"
2319 " gl_FragColor = foo;\n"
2320 "}";
2321
2322 GLuint program = CompileProgram(vertexShader, fragmentShader);
2323 EXPECT_EQ(0u, program);
2324}
2325
Geoff Lang966c9402017-04-18 12:38:27 -04002326// Test dimension and image size validation of compressed textures
2327TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
2328{
2329 if (extensionRequestable("GL_EXT_texture_compression_dxt1"))
2330 {
2331 glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
2332 }
2333
Yunchao He9550c602018-02-13 14:47:05 +08002334 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_texture_compression_dxt1"));
Geoff Lang966c9402017-04-18 12:38:27 -04002335
2336 constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
2337
2338 GLTexture texture;
2339 glBindTexture(GL_TEXTURE_2D, texture);
2340
2341 // Regular case, verify that it works
2342 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2343 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2344 ASSERT_GL_NO_ERROR();
2345
2346 // Test various dimensions that are not valid
2347 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
2348 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2349 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2350
2351 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
2352 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2353 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2354
2355 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2356 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2357 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2358
2359 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2360 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2361 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2362
2363 // Test various image sizes that are not valid
2364 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2365 sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
2366 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2367
2368 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2369 sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
2370 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2371
2372 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
2373 CompressedImageDXT1);
2374 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2375
2376 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
2377 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2378 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2379
2380 // Fill a full mip chain and verify that it works
2381 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2382 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2383 glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2384 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2385 glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2386 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2387 ASSERT_GL_NO_ERROR();
2388
2389 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2390 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2391 ASSERT_GL_NO_ERROR();
2392
2393 // Test that non-block size sub-uploads are not valid for the 0 mip
2394 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2395 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2396 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2397
2398 // Test that non-block size sub-uploads are valid for if they fill the whole mip
2399 glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2400 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2401 glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2402 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2403 ASSERT_GL_NO_ERROR();
2404
2405 // Test that if the format miss-matches the texture, an error is generated
2406 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
2407 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2408 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2409}
2410
Geoff Lang677bb6f2017-04-05 12:40:40 -04002411TEST_P(WebGLCompatibilityTest, L32FTextures)
2412{
2413 constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f};
2414 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
2415
2416 for (auto extension : FloatingPointTextureExtensions)
2417 {
2418 if (strlen(extension) > 0 && extensionRequestable(extension))
2419 {
2420 glRequestExtensionANGLE(extension);
2421 ASSERT_GL_NO_ERROR();
2422 }
2423
2424 // Unsized L 32F
2425 {
2426 bool texture = extensionEnabled("GL_OES_texture_float");
2427 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2428 bool render = false;
2429 TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
2430 textureData, readPixelData);
2431 }
2432
2433 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2434 {
2435 // Sized L 32F
2436 bool texture = extensionEnabled("GL_OES_texture_float") &&
2437 extensionEnabled("GL_EXT_texture_storage");
2438 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2439 bool render = false;
2440 TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
2441 render, textureData, readPixelData);
2442 }
2443 }
2444}
2445
2446TEST_P(WebGLCompatibilityTest, A32FTextures)
2447{
2448 constexpr float textureData[] = {33.33f, 0.0f, 0.0f, 0.0f};
2449 constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
2450
2451 for (auto extension : FloatingPointTextureExtensions)
2452 {
2453 if (strlen(extension) > 0 && extensionRequestable(extension))
2454 {
2455 glRequestExtensionANGLE(extension);
2456 ASSERT_GL_NO_ERROR();
2457 }
2458
2459 // Unsized A 32F
2460 {
2461 bool texture = extensionEnabled("GL_OES_texture_float");
2462 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2463 bool render = false;
2464 TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
2465 textureData, readPixelData);
2466 }
2467
2468 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2469 {
2470 // Sized A 32F
2471 bool texture = extensionEnabled("GL_OES_texture_float") &&
2472 extensionEnabled("GL_EXT_texture_storage");
2473 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2474 bool render = false;
2475 TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
2476 textureData, readPixelData);
2477 }
2478 }
2479}
2480
2481TEST_P(WebGLCompatibilityTest, LA32FTextures)
2482{
2483 constexpr float textureData[] = {-0.21f, 15.1f, 0.0f, 0.0f};
2484 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
2485 textureData[1]};
2486
2487 for (auto extension : FloatingPointTextureExtensions)
2488 {
2489 if (strlen(extension) > 0 && extensionRequestable(extension))
2490 {
2491 glRequestExtensionANGLE(extension);
2492 ASSERT_GL_NO_ERROR();
2493 }
2494
2495 // Unsized LA 32F
2496 {
2497 bool texture = extensionEnabled("GL_OES_texture_float");
2498 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2499 bool render = false;
2500 TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
2501 filter, render, textureData, readPixelData);
2502 }
2503
2504 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2505 {
2506 // Sized LA 32F
2507 bool texture = extensionEnabled("GL_OES_texture_float") &&
2508 extensionEnabled("GL_EXT_texture_storage");
2509 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2510 bool render = false;
2511 TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
2512 filter, render, textureData, readPixelData);
2513 }
2514 }
2515}
2516
2517TEST_P(WebGLCompatibilityTest, R32FTextures)
2518{
2519 constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
2520
2521 for (auto extension : FloatingPointTextureExtensions)
2522 {
2523 if (strlen(extension) > 0 && extensionRequestable(extension))
2524 {
2525 glRequestExtensionANGLE(extension);
2526 ASSERT_GL_NO_ERROR();
2527 }
2528
2529 // Unsized R 32F
2530 {
2531 bool texture =
2532 extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg");
2533 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2534 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2535 TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
2536 }
2537
2538 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2539 {
2540 // Sized R 32F
2541 bool texture =
2542 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2543 extensionEnabled("GL_EXT_texture_rg") &&
2544 extensionEnabled("GL_EXT_texture_storage"));
2545 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2546 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2547 TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
2548 }
2549 }
2550}
2551
2552TEST_P(WebGLCompatibilityTest, RG32FTextures)
2553{
2554 constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
2555
2556 for (auto extension : FloatingPointTextureExtensions)
2557 {
2558 if (strlen(extension) > 0 && extensionRequestable(extension))
2559 {
2560 glRequestExtensionANGLE(extension);
2561 ASSERT_GL_NO_ERROR();
2562 }
2563
2564 // Unsized RG 32F
2565 {
2566 bool texture =
2567 (extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg"));
2568 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2569 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2570 TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
2571 }
2572
2573 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2574 {
2575 // Sized RG 32F
2576 bool texture =
2577 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2578 extensionEnabled("GL_EXT_texture_rg") &&
2579 extensionEnabled("GL_EXT_texture_storage"));
2580 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2581 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2582 TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
2583 }
2584 }
2585}
2586
2587TEST_P(WebGLCompatibilityTest, RGB32FTextures)
2588{
Yunchao He9550c602018-02-13 14:47:05 +08002589 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel());
Geoff Lang40762ef2017-05-08 13:47:03 -04002590
Geoff Lang677bb6f2017-04-05 12:40:40 -04002591 constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
2592
2593 for (auto extension : FloatingPointTextureExtensions)
2594 {
2595 if (strlen(extension) > 0 && extensionRequestable(extension))
2596 {
2597 glRequestExtensionANGLE(extension);
2598 ASSERT_GL_NO_ERROR();
2599 }
2600
2601 // Unsized RGB 32F
2602 {
2603 bool texture = extensionEnabled("GL_OES_texture_float");
2604 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2605 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
2606 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
2607 }
2608
2609 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2610 {
2611 // Sized RGBA 32F
2612 bool texture =
2613 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2614 extensionEnabled("GL_EXT_texture_storage"));
2615 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2616 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
2617 TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
2618 data);
2619 }
2620 }
2621}
2622
2623TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
2624{
2625 constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2626
2627 for (auto extension : FloatingPointTextureExtensions)
2628 {
2629 if (strlen(extension) > 0 && extensionRequestable(extension))
2630 {
2631 glRequestExtensionANGLE(extension);
2632 ASSERT_GL_NO_ERROR();
2633 }
2634
2635 // Unsized RGBA 32F
2636 {
2637 bool texture = extensionEnabled("GL_OES_texture_float");
2638 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2639 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2640 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2641 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
2642 }
2643
2644 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2645 {
2646 // Sized RGBA 32F
2647 bool texture =
2648 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2649 extensionEnabled("GL_EXT_texture_storage"));
2650 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2651 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2652 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2653 TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
2654 data);
2655 }
2656 }
2657}
2658
2659TEST_P(WebGLCompatibilityTest, R16FTextures)
2660{
2661 constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
2662 const GLushort textureData[] = {
2663 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2664 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2665
2666 for (auto extension : FloatingPointTextureExtensions)
2667 {
2668 if (strlen(extension) > 0 && extensionRequestable(extension))
2669 {
2670 glRequestExtensionANGLE(extension);
2671 ASSERT_GL_NO_ERROR();
2672 }
2673
2674 // Unsized R 16F (OES)
2675 {
2676 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2677 extensionEnabled("GL_EXT_texture_rg");
2678 bool filter = getClientMajorVersion() >= 3 ||
2679 extensionEnabled("GL_OES_texture_half_float_linear");
2680 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2681 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
2682 textureData, readPixelsData);
2683 }
2684
2685 // Unsized R 16F
2686 {
2687 bool texture = false;
2688 bool filter = false;
2689 bool render = false;
2690 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2691 textureData, readPixelsData);
2692 }
2693
2694 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2695 {
2696 // Sized R 16F
2697 bool texture = getClientMajorVersion() >= 3;
2698 bool filter = getClientMajorVersion() >= 3 ||
2699 extensionEnabled("GL_OES_texture_half_float_linear");
2700 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2701 extensionEnabled("GL_EXT_color_buffer_float");
2702 TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2703 textureData, readPixelsData);
2704 }
2705 }
2706}
2707
2708TEST_P(WebGLCompatibilityTest, RG16FTextures)
2709{
2710 constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
2711 const GLushort textureData[] = {
2712 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2713 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2714
2715 for (auto extension : FloatingPointTextureExtensions)
2716 {
2717 if (strlen(extension) > 0 && extensionRequestable(extension))
2718 {
2719 glRequestExtensionANGLE(extension);
2720 ASSERT_GL_NO_ERROR();
2721 }
2722
2723 // Unsized RG 16F (OES)
2724 {
2725 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2726 extensionEnabled("GL_EXT_texture_rg");
2727 bool filter = getClientMajorVersion() >= 3 ||
2728 extensionEnabled("GL_OES_texture_half_float_linear");
2729 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") &&
2730 extensionEnabled("GL_EXT_texture_rg");
2731 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
2732 textureData, readPixelsData);
2733 }
2734
2735 // Unsized RG 16F
2736 {
2737 bool texture = false;
2738 bool filter = false;
2739 bool render = false;
2740 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2741 textureData, readPixelsData);
2742 }
2743
2744 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2745 {
2746 // Sized RG 16F
2747 bool texture = getClientMajorVersion() >= 3;
2748 bool filter = getClientMajorVersion() >= 3 ||
2749 extensionEnabled("GL_OES_texture_half_float_linear");
2750 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2751 extensionEnabled("GL_EXT_color_buffer_float");
2752 TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2753 textureData, readPixelsData);
2754 }
2755 }
2756}
2757
2758TEST_P(WebGLCompatibilityTest, RGB16FTextures)
2759{
Yunchao He9550c602018-02-13 14:47:05 +08002760 ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
Geoff Lang40762ef2017-05-08 13:47:03 -04002761
Geoff Lang677bb6f2017-04-05 12:40:40 -04002762 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
2763 const GLushort textureData[] = {
2764 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2765 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2766
2767 for (auto extension : FloatingPointTextureExtensions)
2768 {
2769 if (strlen(extension) > 0 && extensionRequestable(extension))
2770 {
2771 glRequestExtensionANGLE(extension);
2772 ASSERT_GL_NO_ERROR();
2773 }
2774
2775 // Unsized RGB 16F (OES)
2776 {
2777 bool texture = extensionEnabled("GL_OES_texture_half_float");
2778 bool filter = getClientMajorVersion() >= 3 ||
2779 extensionEnabled("GL_OES_texture_half_float_linear");
2780 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2781 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
2782 textureData, readPixelsData);
2783 }
2784
2785 // Unsized RGB 16F
2786 {
2787 bool texture = false;
2788 bool filter = false;
2789 bool render = false;
2790 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2791 textureData, readPixelsData);
2792 }
2793
2794 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2795 {
2796 // Sized RGB 16F
2797 bool texture = getClientMajorVersion() >= 3;
2798 bool filter = getClientMajorVersion() >= 3 ||
2799 extensionEnabled("GL_OES_texture_half_float_linear");
2800 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2801 TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2802 textureData, readPixelsData);
2803 }
2804 }
2805}
2806
2807TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
2808{
Yunchao He9550c602018-02-13 14:47:05 +08002809 ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
Geoff Lang40762ef2017-05-08 13:47:03 -04002810
Geoff Lang677bb6f2017-04-05 12:40:40 -04002811 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2812 const GLushort textureData[] = {
2813 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2814 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2815
2816 for (auto extension : FloatingPointTextureExtensions)
2817 {
2818 if (strlen(extension) > 0 && extensionRequestable(extension))
2819 {
2820 glRequestExtensionANGLE(extension);
2821 ASSERT_GL_NO_ERROR();
2822 }
2823
2824 // Unsized RGBA 16F (OES)
2825 {
2826 bool texture = extensionEnabled("GL_OES_texture_half_float");
2827 bool filter = getClientMajorVersion() >= 3 ||
2828 extensionEnabled("GL_OES_texture_half_float_linear");
2829 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2830 extensionEnabled("GL_EXT_color_buffer_float");
2831 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
2832 textureData, readPixelsData);
2833 }
2834
2835 // Unsized RGBA 16F
2836 {
2837 bool texture = false;
2838 bool filter = false;
2839 bool render = false;
2840 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2841 textureData, readPixelsData);
2842 }
2843
2844 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2845 {
2846 // Sized RGBA 16F
2847 bool texture = getClientMajorVersion() >= 3;
2848 bool filter = getClientMajorVersion() >= 3 ||
2849 extensionEnabled("GL_OES_texture_half_float_linear");
2850 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2851 extensionEnabled("GL_EXT_color_buffer_float");
2852 TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2853 textureData, readPixelsData);
2854 }
2855 }
2856}
2857
Geoff Lang6e898aa2017-06-02 11:17:26 -04002858// Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
2859// accepted by glTexImage2D
2860TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
2861{
Yunchao He9550c602018-02-13 14:47:05 +08002862 // Test skipped because it is only valid for WebGL1 contexts.
2863 ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
Geoff Lang6e898aa2017-06-02 11:17:26 -04002864
Yunchao He9550c602018-02-13 14:47:05 +08002865 ANGLE_SKIP_TEST_IF(!extensionRequestable("GL_OES_texture_float"));
2866
Geoff Lang6e898aa2017-06-02 11:17:26 -04002867 glRequestExtensionANGLE("GL_OES_texture_float");
2868 ASSERT_GL_NO_ERROR();
2869
2870 GLTexture texture;
2871 glBindTexture(GL_TEXTURE_2D, texture);
2872
2873 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2874 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2875
2876 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2877 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2878
2879 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
2880 {
2881 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
2882 ASSERT_GL_NO_ERROR();
2883
2884 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2885 EXPECT_GL_NO_ERROR();
2886 }
2887
2888 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
2889 {
2890 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
2891 ASSERT_GL_NO_ERROR();
2892
2893 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2894 EXPECT_GL_NO_ERROR();
2895 }
2896}
2897
Bryan Bernhart (Intel Americas Inc)491b0d62017-11-10 12:48:22 -08002898// Verify GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point.
2899TEST_P(WebGLCompatibilityTest, DepthStencilAttachment)
2900{
2901 ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
2902
2903 // Test that attaching a bound texture succeeds.
2904 GLTexture texture;
2905 glBindTexture(GL_TEXTURE_2D, texture);
2906
2907 GLFramebuffer fbo;
2908 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2909
2910 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
2911
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -08002912 GLint attachmentType = 0;
Bryan Bernhart (Intel Americas Inc)491b0d62017-11-10 12:48:22 -08002913 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -08002914 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
Bryan Bernhart (Intel Americas Inc)491b0d62017-11-10 12:48:22 -08002915 EXPECT_GL_NO_ERROR();
2916 EXPECT_GLENUM_EQ(GL_TEXTURE, attachmentType);
2917
2918 // Test when if no attach object at the named attachment point and pname is not OBJECT_TYPE.
2919 GLFramebuffer fbo2;
2920 glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
2921
2922 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -08002923 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attachmentType);
Bryan Bernhart (Intel Americas Inc)491b0d62017-11-10 12:48:22 -08002924 EXPECT_GL_ERROR(GL_INVALID_ENUM);
2925}
2926
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -08002927// Verify framebuffer attachments return expected types when in an inconsistant state.
2928TEST_P(WebGLCompatibilityTest, FramebufferAttachmentConsistancy)
2929{
2930 ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
2931
2932 GLFramebuffer fbo;
2933 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2934
2935 GLRenderbuffer rb1;
2936 glBindRenderbuffer(GL_RENDERBUFFER, rb1);
2937
2938 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb1);
2939
2940 GLint attachmentType = 0;
2941 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
2942 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
2943
2944 EXPECT_GL_NO_ERROR();
2945 EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
2946
2947 GLRenderbuffer rb2;
2948 glBindRenderbuffer(GL_RENDERBUFFER, rb2);
2949
2950 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb2);
2951
2952 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
2953 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
2954
2955 EXPECT_GL_NO_ERROR();
2956 EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
Bryan Bernhart (Intel Americas Inc)5f198102017-12-12 14:21:39 -08002957
2958 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb2);
2959
2960 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
2961 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
2962
2963 EXPECT_GL_NO_ERROR();
2964 EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
2965
2966 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb2);
2967
2968 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
2969 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &attachmentType);
2970
2971 EXPECT_GL_NO_ERROR();
2972 EXPECT_GLENUM_EQ(GL_RENDERBUFFER, attachmentType);
Bryan Bernhart (Intel Americas Inc)2eeb1b32017-11-29 16:06:43 -08002973}
2974
Jamie Madill07be8bf2017-02-02 19:59:57 -05002975// This tests that rendering feedback loops works as expected with WebGL 2.
2976// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
2977TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
2978{
2979 const std::string vertexShader =
2980 "#version 300 es\n"
2981 "in vec4 aPosition;\n"
2982 "out vec2 texCoord;\n"
2983 "void main() {\n"
2984 " gl_Position = aPosition;\n"
2985 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2986 "}\n";
2987
2988 const std::string fragmentShader =
2989 "#version 300 es\n"
2990 "precision mediump float;\n"
2991 "uniform sampler2D tex;\n"
2992 "in vec2 texCoord;\n"
2993 "out vec4 oColor;\n"
2994 "void main() {\n"
2995 " oColor = texture(tex, texCoord);\n"
2996 "}\n";
2997
2998 GLsizei width = 8;
2999 GLsizei height = 8;
3000
3001 GLint maxDrawBuffers = 0;
3002 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3003 // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
3004 ASSERT_GE(maxDrawBuffers, 2);
3005
3006 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3007 glUseProgram(program.get());
3008 glViewport(0, 0, width, height);
3009
3010 GLTexture tex0;
3011 GLTexture tex1;
3012 GLFramebuffer fbo;
3013 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
3014 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
3015 ASSERT_GL_NO_ERROR();
3016
3017 glBindTexture(GL_TEXTURE_2D, tex1.get());
3018 GLint texLoc = glGetUniformLocation(program.get(), "tex");
3019 ASSERT_NE(-1, texLoc);
3020 glUniform1i(texLoc, 0);
3021
3022 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
3023 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
3024 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
3025 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
3026 ASSERT_GL_NO_ERROR();
3027
3028 drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
3029 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
3030 GL_INVALID_OPERATION);
3031 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
3032}
3033
Jamie Madill1d37bc52017-02-02 19:59:58 -05003034// This test covers detection of rendering feedback loops between the FBO and a depth Texture.
3035// Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
3036TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
3037{
3038 const std::string vertexShader =
3039 "#version 300 es\n"
3040 "in vec4 aPosition;\n"
3041 "out vec2 texCoord;\n"
3042 "void main() {\n"
3043 " gl_Position = aPosition;\n"
3044 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
3045 "}\n";
3046
3047 const std::string fragmentShader =
3048 "#version 300 es\n"
3049 "precision mediump float;\n"
3050 "uniform sampler2D tex;\n"
3051 "in vec2 texCoord;\n"
3052 "out vec4 oColor;\n"
3053 "void main() {\n"
3054 " oColor = texture(tex, texCoord);\n"
3055 "}\n";
3056
3057 GLsizei width = 8;
3058 GLsizei height = 8;
3059
3060 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3061 glUseProgram(program.get());
3062
3063 glViewport(0, 0, width, height);
3064
3065 GLint texLoc = glGetUniformLocation(program.get(), "tex");
3066 glUniform1i(texLoc, 0);
3067
3068 // Create textures and allocate storage
3069 GLTexture tex0;
3070 GLTexture tex1;
3071 GLRenderbuffer rb;
3072 FillTexture2D(tex0.get(), width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
3073 FillTexture2D(tex1.get(), width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
3074 GL_UNSIGNED_INT);
3075 glBindRenderbuffer(GL_RENDERBUFFER, rb.get());
3076 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
3077 ASSERT_GL_NO_ERROR();
3078
3079 GLFramebuffer fbo;
3080 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
3081 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
3082
3083 // Test rendering and sampling feedback loop for depth buffer
3084 glBindTexture(GL_TEXTURE_2D, tex1.get());
3085 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1.get(), 0);
3086 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3087
3088 // The same image is used as depth buffer during rendering.
3089 glEnable(GL_DEPTH_TEST);
3090 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
3091 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3092
3093 // The same image is used as depth buffer. But depth mask is false.
3094 glDepthMask(GL_FALSE);
3095 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
3096 EXPECT_GL_NO_ERROR();
3097
3098 // The same image is used as depth buffer. But depth test is not enabled during rendering.
3099 glDepthMask(GL_TRUE);
3100 glDisable(GL_DEPTH_TEST);
3101 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
3102 EXPECT_GL_NO_ERROR();
3103
3104 // Test rendering and sampling feedback loop for stencil buffer
3105 glBindTexture(GL_RENDERBUFFER, rb.get());
3106 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
3107 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb.get());
3108 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
3109 constexpr GLint stencilClearValue = 0x40;
3110 glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
3111
3112 // The same image is used as stencil buffer during rendering.
3113 glEnable(GL_STENCIL_TEST);
3114 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
3115 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3116
3117 // The same image is used as stencil buffer. But stencil mask is zero.
3118 glStencilMask(0x0);
3119 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
3120 EXPECT_GL_NO_ERROR();
3121
3122 // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
3123 glStencilMask(0xffff);
3124 glDisable(GL_STENCIL_TEST);
3125 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
3126 EXPECT_GL_NO_ERROR();
3127}
3128
Jamie Madillfd3dd432017-02-02 19:59:59 -05003129// The source and the target for CopyTexSubImage3D are the same 3D texture.
3130// But the level of the 3D texture != the level of the read attachment.
3131TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
3132{
3133 GLTexture texture;
3134 GLFramebuffer framebuffer;
3135
3136 glBindTexture(GL_TEXTURE_3D, texture.get());
3137 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
3138
3139 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3140 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3141 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
3142 ASSERT_GL_NO_ERROR();
3143
3144 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
3145 EXPECT_GL_NO_ERROR();
3146}
3147
3148// The source and the target for CopyTexSubImage3D are the same 3D texture.
3149// But the zoffset of the 3D texture != the layer of the read attachment.
3150TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
3151{
3152 GLTexture texture;
3153 GLFramebuffer framebuffer;
3154
3155 glBindTexture(GL_TEXTURE_3D, texture.get());
3156 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
3157
3158 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3159 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 1);
3160 ASSERT_GL_NO_ERROR();
3161
3162 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
3163 EXPECT_GL_NO_ERROR();
3164}
3165
3166// The source and the target for CopyTexSubImage3D are the same 3D texture.
3167// And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
3168TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
3169{
3170 GLTexture texture;
3171 GLFramebuffer framebuffer;
3172
3173 glBindTexture(GL_TEXTURE_3D, texture.get());
3174 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
3175
3176 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3177 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3178 glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3179 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 1, 0);
3180 ASSERT_GL_NO_ERROR();
3181
3182 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
3183 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3184}
3185
Corentin Wallez59c41592017-07-11 13:19:54 -04003186// Verify that errors are generated when there isn't a defined conversion between the clear type and
3187// the buffer type.
Geoff Lang76e65652017-03-27 14:58:02 -04003188TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
3189{
Yunchao He9550c602018-02-13 14:47:05 +08003190 // Test skipped for D3D11 because it generates D3D11 runtime warnings.
3191 ANGLE_SKIP_TEST_IF(IsD3D11());
Geoff Lang76e65652017-03-27 14:58:02 -04003192
3193 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
3194 constexpr int clearInt[] = {0, 0, 0, 0};
3195 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
3196
3197 GLTexture texture;
3198 GLFramebuffer framebuffer;
3199
3200 glBindTexture(GL_TEXTURE_2D, texture.get());
3201 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
3202
3203 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
3204 ASSERT_GL_NO_ERROR();
3205
3206 // Unsigned integer buffer
3207 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
3208 ASSERT_GL_NO_ERROR();
3209
3210 glClearBufferfv(GL_COLOR, 0, clearFloat);
3211 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3212
3213 glClearBufferiv(GL_COLOR, 0, clearInt);
3214 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3215
3216 glClearBufferuiv(GL_COLOR, 0, clearUint);
3217 EXPECT_GL_NO_ERROR();
3218
3219 glClear(GL_COLOR_BUFFER_BIT);
3220 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3221
3222 // Integer buffer
3223 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
3224 ASSERT_GL_NO_ERROR();
3225
3226 glClearBufferfv(GL_COLOR, 0, clearFloat);
3227 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3228
3229 glClearBufferiv(GL_COLOR, 0, clearInt);
3230 EXPECT_GL_NO_ERROR();
3231
3232 glClearBufferuiv(GL_COLOR, 0, clearUint);
3233 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3234
3235 glClear(GL_COLOR_BUFFER_BIT);
3236 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3237
3238 // Float buffer
Geoff Lang677bb6f2017-04-05 12:40:40 -04003239 if (extensionRequestable("GL_EXT_color_buffer_float"))
3240 {
3241 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
3242 }
Geoff Lang76e65652017-03-27 14:58:02 -04003243
Geoff Lang677bb6f2017-04-05 12:40:40 -04003244 if (extensionEnabled("GL_EXT_color_buffer_float"))
3245 {
3246 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
3247 ASSERT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04003248
Geoff Lang677bb6f2017-04-05 12:40:40 -04003249 glClearBufferfv(GL_COLOR, 0, clearFloat);
3250 EXPECT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04003251
Geoff Lang677bb6f2017-04-05 12:40:40 -04003252 glClearBufferiv(GL_COLOR, 0, clearInt);
3253 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang76e65652017-03-27 14:58:02 -04003254
Geoff Lang677bb6f2017-04-05 12:40:40 -04003255 glClearBufferuiv(GL_COLOR, 0, clearUint);
3256 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3257
3258 glClear(GL_COLOR_BUFFER_BIT);
3259 EXPECT_GL_NO_ERROR();
3260 }
Geoff Lang76e65652017-03-27 14:58:02 -04003261
3262 // Normalized uint buffer
3263 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3264 ASSERT_GL_NO_ERROR();
3265
3266 glClearBufferfv(GL_COLOR, 0, clearFloat);
3267 EXPECT_GL_NO_ERROR();
3268
3269 glClearBufferiv(GL_COLOR, 0, clearInt);
3270 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3271
3272 glClearBufferuiv(GL_COLOR, 0, clearUint);
3273 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3274
3275 glClear(GL_COLOR_BUFFER_BIT);
3276 EXPECT_GL_NO_ERROR();
3277}
3278
Corentin Wallez59c41592017-07-11 13:19:54 -04003279// Test the interaction of WebGL compatibility clears with default framebuffers
3280TEST_P(WebGL2CompatibilityTest, ClearBufferDefaultFramebuffer)
3281{
3282 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
3283 constexpr int clearInt[] = {0, 0, 0, 0};
3284 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
3285
3286 // glClear works as usual, this is also a regression test for a bug where we
3287 // iterated on maxDrawBuffers for default framebuffers, triggering an assert
3288 glClear(GL_COLOR_BUFFER_BIT);
3289 EXPECT_GL_NO_ERROR();
3290
3291 // Default framebuffers are normalized uints, so only glClearBufferfv works.
3292 glClearBufferfv(GL_COLOR, 0, clearFloat);
3293 EXPECT_GL_NO_ERROR();
3294
3295 glClearBufferiv(GL_COLOR, 0, clearInt);
3296 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3297
3298 glClearBufferuiv(GL_COLOR, 0, clearUint);
3299 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3300}
3301
Geoff Lange4915782017-04-12 15:19:07 -04003302// Verify that errors are generate when trying to blit from an image to itself
3303TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
3304{
3305 GLTexture textures[2];
3306 glBindTexture(GL_TEXTURE_2D, textures[0]);
3307 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
3308 glBindTexture(GL_TEXTURE_2D, textures[1]);
3309 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
3310
3311 GLRenderbuffer renderbuffers[2];
3312 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
3313 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
3314 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
3315 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
3316
3317 GLFramebuffer framebuffers[2];
3318 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
3319 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
3320
3321 ASSERT_GL_NO_ERROR();
3322
3323 // Same texture
3324 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3325 0);
3326 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3327 0);
3328 ASSERT_GL_NO_ERROR();
3329 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3330 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3331
3332 // Same textures but different renderbuffers
3333 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3334 renderbuffers[0]);
3335 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3336 renderbuffers[1]);
3337 ASSERT_GL_NO_ERROR();
3338 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
3339 ASSERT_GL_NO_ERROR();
3340 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3341 GL_NEAREST);
3342 ASSERT_GL_NO_ERROR();
3343 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
3344 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3345 GL_NEAREST);
3346 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3347
3348 // Same renderbuffers but different textures
3349 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3350 0);
3351 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
3352 0);
3353 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3354 renderbuffers[0]);
3355 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3356 renderbuffers[0]);
3357 ASSERT_GL_NO_ERROR();
3358 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3359 ASSERT_GL_NO_ERROR();
3360 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3361 GL_NEAREST);
3362 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3363 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
3364 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3365 GL_NEAREST);
3366 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3367}
3368
Geoff Lange0cff192017-05-30 13:04:56 -04003369// Verify that errors are generated when the fragment shader output doesn't match the bound color
3370// buffer types
3371TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
3372{
3373 const std::string vertexShader =
3374 "#version 300 es\n"
3375 "void main() {\n"
3376 " gl_Position = vec4(0, 0, 0, 1);\n"
3377 "}\n";
3378
3379 const std::string fragmentShader =
3380 "#version 300 es\n"
3381 "precision mediump float;\n"
3382 "layout(location = 0) out vec4 floatOutput;\n"
3383 "layout(location = 1) out uvec4 uintOutput;\n"
3384 "layout(location = 2) out ivec4 intOutput;\n"
3385 "void main() {\n"
3386 " floatOutput = vec4(0, 0, 0, 1);\n"
3387 " uintOutput = uvec4(0, 0, 0, 1);\n"
3388 " intOutput = ivec4(0, 0, 0, 1);\n"
3389 "}\n";
3390
3391 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3392 glUseProgram(program.get());
3393
3394 GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
3395 GLuint uintLocation = glGetFragDataLocation(program, "uintOutput");
3396 GLuint intLocation = glGetFragDataLocation(program, "intOutput");
3397
3398 GLFramebuffer fbo;
3399 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3400
3401 GLRenderbuffer floatRenderbuffer;
3402 glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
3403 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
3404 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
3405 floatRenderbuffer);
3406
3407 GLRenderbuffer uintRenderbuffer;
3408 glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
3409 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
3410 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3411 uintRenderbuffer);
3412
3413 GLRenderbuffer intRenderbuffer;
3414 glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
3415 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
3416 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3417 intRenderbuffer);
3418
3419 ASSERT_GL_NO_ERROR();
3420
3421 GLint maxDrawBuffers = 0;
3422 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3423 std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
3424 drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
3425 drawBuffers[uintLocation] = GL_COLOR_ATTACHMENT0 + uintLocation;
3426 drawBuffers[intLocation] = GL_COLOR_ATTACHMENT0 + intLocation;
3427
3428 glDrawBuffers(maxDrawBuffers, drawBuffers.data());
3429
3430 // Check that the correct case generates no errors
3431 glDrawArrays(GL_TRIANGLES, 0, 6);
3432 EXPECT_GL_NO_ERROR();
3433
3434 // Unbind some buffers and verify that there are still no errors
3435 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3436 0);
3437 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3438 0);
3439 glDrawArrays(GL_TRIANGLES, 0, 6);
3440 EXPECT_GL_NO_ERROR();
3441
3442 // Swap the int and uint buffers to and verify that an error is generated
3443 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3444 intRenderbuffer);
3445 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3446 uintRenderbuffer);
3447 glDrawArrays(GL_TRIANGLES, 0, 6);
3448 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3449
3450 // Swap the float and uint buffers to and verify that an error is generated
3451 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3452 floatRenderbuffer);
3453 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
3454 uintRenderbuffer);
3455 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3456 intRenderbuffer);
3457 glDrawArrays(GL_TRIANGLES, 0, 6);
3458 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3459}
3460
Geoff Lang9ab5b822017-05-30 16:19:23 -04003461// Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
3462// types
Corentin Wallezc3bc9842017-10-11 15:15:59 -04003463TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMismatch)
Geoff Lang9ab5b822017-05-30 16:19:23 -04003464{
3465 const std::string vertexShader =
3466 "#version 300 es\n"
3467 "in vec4 floatInput;\n"
3468 "in uvec4 uintInput;\n"
3469 "in ivec4 intInput;\n"
3470 "void main() {\n"
3471 " gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);\n"
3472 "}\n";
3473
3474 const std::string fragmentShader =
3475 "#version 300 es\n"
3476 "precision mediump float;\n"
3477 "out vec4 outputColor;\n"
3478 "void main() {\n"
3479 " outputColor = vec4(0, 0, 0, 1);"
3480 "}\n";
3481
3482 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3483 glUseProgram(program.get());
3484
3485 GLint floatLocation = glGetAttribLocation(program, "floatInput");
3486 GLint uintLocation = glGetAttribLocation(program, "uintInput");
3487 GLint intLocation = glGetAttribLocation(program, "intInput");
3488
3489 // Default attributes are of float types
3490 glDrawArrays(GL_TRIANGLES, 0, 6);
3491 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3492
3493 // Set the default attributes to the correct types, should succeed
3494 glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
3495 glVertexAttribI4i(intLocation, 0, 0, 0, 1);
3496 glDrawArrays(GL_TRIANGLES, 0, 6);
3497 EXPECT_GL_NO_ERROR();
3498
3499 // Change the default float attribute to an integer, should fail
3500 glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
3501 glDrawArrays(GL_TRIANGLES, 0, 6);
3502 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3503
3504 // Use a buffer for some attributes
3505 GLBuffer buffer;
3506 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3507 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
3508 glEnableVertexAttribArray(floatLocation);
3509 glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
3510 glDrawArrays(GL_TRIANGLES, 0, 6);
3511 EXPECT_GL_NO_ERROR();
3512
3513 // Use a float pointer attrib for a uint input
3514 glEnableVertexAttribArray(uintLocation);
3515 glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
3516 glDrawArrays(GL_TRIANGLES, 0, 6);
3517 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3518
3519 // Use a uint pointer for the uint input
3520 glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
3521 glDrawArrays(GL_TRIANGLES, 0, 6);
3522 EXPECT_GL_NO_ERROR();
3523}
3524
Geoff Langfa125c92017-10-24 13:01:46 -04003525// Test that it's not possible to query the non-zero color attachments without the drawbuffers
3526// extension in WebGL1
3527TEST_P(WebGLCompatibilityTest, FramebufferAttachmentQuery)
3528{
3529 ANGLE_SKIP_TEST_IF(getClientMajorVersion() > 2);
3530 ANGLE_SKIP_TEST_IF(extensionEnabled("GL_EXT_draw_buffers"));
3531
3532 GLFramebuffer fbo;
3533 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3534 EXPECT_GL_NO_ERROR();
3535
3536 GLint result;
3537 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
3538 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &result);
3539 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3540
3541 GLRenderbuffer renderbuffer;
3542 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
3543 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
3544 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, renderbuffer);
3545 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3546}
3547
Corentin Walleze7557742017-06-01 13:09:57 -04003548// Tests the WebGL removal of undefined behavior when attachments aren't written to.
3549TEST_P(WebGLCompatibilityTest, DrawBuffers)
3550{
Corentin Walleze7557742017-06-01 13:09:57 -04003551 // Make sure we can use at least 4 attachments for the tests.
3552 bool useEXT = false;
3553 if (getClientMajorVersion() < 3)
3554 {
Yunchao He9550c602018-02-13 14:47:05 +08003555 ANGLE_SKIP_TEST_IF(!extensionRequestable("GL_EXT_draw_buffers"));
Corentin Walleze7557742017-06-01 13:09:57 -04003556
3557 glRequestExtensionANGLE("GL_EXT_draw_buffers");
3558 useEXT = true;
3559 EXPECT_GL_NO_ERROR();
3560 }
3561
3562 GLint maxDrawBuffers = 0;
3563 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
Yunchao He9550c602018-02-13 14:47:05 +08003564 // Test skipped because MAX_DRAW_BUFFERS is too small.
3565 ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
Corentin Walleze7557742017-06-01 13:09:57 -04003566
3567 // Clears all the renderbuffers to red.
3568 auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
3569 GLFramebuffer clearFBO;
Geoff Lange8afa902017-09-27 15:00:43 -04003570 glBindFramebuffer(GL_FRAMEBUFFER, clearFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003571
3572 glClearColor(1, 0, 0, 1);
3573 for (int i = 0; i < 4; ++i)
3574 {
Geoff Lange8afa902017-09-27 15:00:43 -04003575 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
Corentin Walleze7557742017-06-01 13:09:57 -04003576 renderbuffers[i]);
3577 glClear(GL_COLOR_BUFFER_BIT);
3578 }
3579 ASSERT_GL_NO_ERROR();
3580 };
3581
3582 // Checks that the renderbuffers specified by mask have the correct color
3583 auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
3584 GLFramebuffer readFBO;
Geoff Lange8afa902017-09-27 15:00:43 -04003585 glBindFramebuffer(GL_FRAMEBUFFER, readFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003586
3587 for (int i = 0; i < 4; ++i)
3588 {
3589 if (mask & (1 << i))
3590 {
Geoff Lange8afa902017-09-27 15:00:43 -04003591 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
3592 renderbuffers[i]);
Corentin Walleze7557742017-06-01 13:09:57 -04003593 EXPECT_PIXEL_COLOR_EQ(0, 0, color);
3594 }
3595 }
3596 ASSERT_GL_NO_ERROR();
3597 };
3598
3599 // Depending on whether we are using the extension or ES3, a different entrypoint must be called
3600 auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
3601 if (useEXT)
3602 {
3603 glDrawBuffersEXT(numBuffers, buffers);
3604 }
3605 else
3606 {
3607 glDrawBuffers(numBuffers, buffers);
3608 }
3609 };
3610
3611 // Initialized the test framebuffer
3612 GLFramebuffer drawFBO;
Geoff Lange8afa902017-09-27 15:00:43 -04003613 glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003614
3615 GLRenderbuffer renderbuffers[4];
3616 for (int i = 0; i < 4; ++i)
3617 {
3618 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
Geoff Langd84a00b2017-10-27 17:27:26 -04003619 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 1, 1);
Geoff Lange8afa902017-09-27 15:00:43 -04003620 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
Corentin Walleze7557742017-06-01 13:09:57 -04003621 renderbuffers[i]);
3622 }
3623
3624 ASSERT_GL_NO_ERROR();
3625
3626 const char *vertESSL1 =
3627 "attribute vec4 a_pos;\n"
3628 "void main()\n"
3629 "{\n"
3630 " gl_Position = a_pos;\n"
3631 "}\n";
3632 const char *vertESSL3 =
3633 "#version 300 es\n"
3634 "in vec4 a_pos;\n"
3635 "void main()\n"
3636 "{\n"
3637 " gl_Position = a_pos;\n"
3638 "}\n";
3639
3640 GLenum allDrawBuffers[] = {
3641 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
3642 };
3643
3644 GLenum halfDrawBuffers[] = {
3645 GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
3646 };
3647
3648 // Test that when using gl_FragColor, only the first attachment is written to.
3649 const char *fragESSL1 =
3650 "precision highp float;\n"
3651 "void main()\n"
3652 "{\n"
3653 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
3654 "}\n";
3655 ANGLE_GL_PROGRAM(programESSL1, vertESSL1, fragESSL1);
3656
3657 {
3658 ClearEverythingToRed(renderbuffers);
3659
Geoff Lange8afa902017-09-27 15:00:43 -04003660 glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003661 DrawBuffers(useEXT, 4, allDrawBuffers);
3662 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
3663 ASSERT_GL_NO_ERROR();
3664
3665 CheckColors(renderbuffers, 0b0001, GLColor::green);
3666 CheckColors(renderbuffers, 0b1110, GLColor::red);
3667 }
3668
3669 // Test that when using gl_FragColor, but the first draw buffer is 0, then no attachment is
3670 // written to.
3671 {
3672 ClearEverythingToRed(renderbuffers);
3673
Geoff Lange8afa902017-09-27 15:00:43 -04003674 glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003675 DrawBuffers(useEXT, 4, halfDrawBuffers);
3676 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
3677 ASSERT_GL_NO_ERROR();
3678
3679 CheckColors(renderbuffers, 0b1111, GLColor::red);
3680 }
3681
3682 // Test what happens when rendering to a subset of the outputs. There is a behavior difference
3683 // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
3684 // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
3685 // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
3686 // attachments not declared in the shader should not be written to.
3687 const char *writeOddOutputsVert;
3688 const char *writeOddOutputsFrag;
3689 GLColor unwrittenColor;
3690 if (useEXT)
3691 {
3692 // In the extension, when an attachment isn't written to, it should get 0's
3693 unwrittenColor = GLColor(0, 0, 0, 0);
3694 writeOddOutputsVert = vertESSL1;
3695 writeOddOutputsFrag =
3696 "#extension GL_EXT_draw_buffers : require\n"
3697 "precision highp float;\n"
3698 "void main()\n"
3699 "{\n"
3700 " gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3701 " gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3702 "}\n";
3703 }
3704 else
3705 {
3706 // In ES3 if an attachment isn't declared, it shouldn't get written and should be red
3707 // because of the preceding clears.
3708 unwrittenColor = GLColor::red;
3709 writeOddOutputsVert = vertESSL3;
3710 writeOddOutputsFrag =
3711 "#version 300 es\n"
3712 "precision highp float;\n"
3713 "layout(location = 1) out vec4 output1;"
3714 "layout(location = 3) out vec4 output2;"
3715 "void main()\n"
3716 "{\n"
3717 " output1 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3718 " output2 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3719 "}\n";
3720 }
3721 ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
3722
3723 // Test that attachments not written to get the "unwritten" color
3724 {
3725 ClearEverythingToRed(renderbuffers);
3726
Geoff Lange8afa902017-09-27 15:00:43 -04003727 glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003728 DrawBuffers(useEXT, 4, allDrawBuffers);
3729 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3730 ASSERT_GL_NO_ERROR();
3731
3732 CheckColors(renderbuffers, 0b1010, GLColor::green);
3733 CheckColors(renderbuffers, 0b0101, unwrittenColor);
3734 }
3735
3736 // Test that attachments not written to get the "unwritten" color but that even when the
3737 // extension is used, disabled attachments are not written at all and stay red.
3738 {
3739 ClearEverythingToRed(renderbuffers);
3740
Geoff Lange8afa902017-09-27 15:00:43 -04003741 glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
Corentin Walleze7557742017-06-01 13:09:57 -04003742 DrawBuffers(useEXT, 4, halfDrawBuffers);
3743 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3744 ASSERT_GL_NO_ERROR();
3745
3746 CheckColors(renderbuffers, 0b1000, GLColor::green);
3747 CheckColors(renderbuffers, 0b0100, unwrittenColor);
3748 CheckColors(renderbuffers, 0b0011, GLColor::red);
3749 }
3750}
3751
Geoff Lang536eca12017-09-13 11:23:35 -04003752// Test that it's possible to generate mipmaps on unsized floating point textures once the
3753// extensions have been enabled
3754TEST_P(WebGLCompatibilityTest, GenerateMipmapUnsizedFloatingPointTexture)
3755{
3756 if (extensionRequestable("GL_OES_texture_float"))
3757 {
3758 glRequestExtensionANGLE("GL_OES_texture_float");
3759 }
3760 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_texture_float"));
3761
3762 GLTexture texture;
3763 glBindTexture(GL_TEXTURE_2D, texture);
3764
3765 constexpr GLColor32F data[4] = {
3766 kFloatRed, kFloatRed, kFloatGreen, kFloatBlue,
3767 };
3768 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_FLOAT, data);
3769 ASSERT_GL_NO_ERROR();
3770
3771 glGenerateMipmap(GL_TEXTURE_2D);
3772 EXPECT_GL_NO_ERROR();
3773}
3774// Test that it's possible to generate mipmaps on unsized floating point textures once the
3775// extensions have been enabled
3776TEST_P(WebGLCompatibilityTest, GenerateMipmapSizedFloatingPointTexture)
3777{
3778 if (extensionRequestable("GL_OES_texture_float"))
3779 {
3780 glRequestExtensionANGLE("GL_OES_texture_float");
3781 }
3782 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_texture_float"));
3783
3784 if (extensionRequestable("GL_EXT_texture_storage"))
3785 {
3786 glRequestExtensionANGLE("GL_EXT_texture_storage");
3787 }
3788 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_texture_storage"));
3789
3790 GLTexture texture;
3791 glBindTexture(GL_TEXTURE_2D, texture);
3792
3793 constexpr GLColor32F data[4] = {
3794 kFloatRed, kFloatRed, kFloatGreen, kFloatBlue,
3795 };
3796 glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA32F, 2, 2);
3797 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_FLOAT, data);
3798 ASSERT_GL_NO_ERROR();
3799
3800 glGenerateMipmap(GL_TEXTURE_2D);
3801 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3802
3803 if (extensionRequestable("GL_EXT_color_buffer_float"))
3804 {
3805 // Format is renderable but not filterable
3806 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
3807 glGenerateMipmap(GL_TEXTURE_2D);
3808 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3809 }
3810
3811 if (extensionRequestable("GL_EXT_color_buffer_float_linear"))
3812 {
3813 // Format is renderable but not filterable
3814 glRequestExtensionANGLE("GL_EXT_color_buffer_float_linear");
3815
3816 if (extensionEnabled("GL_EXT_color_buffer_float"))
3817 {
3818 // Format is filterable and renderable
3819 glGenerateMipmap(GL_TEXTURE_2D);
3820 EXPECT_GL_NO_ERROR();
3821 }
3822 else
3823 {
3824 // Format is filterable but not renderable
3825 glGenerateMipmap(GL_TEXTURE_2D);
3826 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3827 }
3828 }
3829}
3830
Bryan Bernhart (Intel Americas Inc)2a357412017-09-05 10:42:47 -07003831// Verify that a texture format is only allowed with extension enabled.
3832void WebGLCompatibilityTest::validateTexImageExtensionFormat(GLenum format,
3833 const std::string &extName)
3834{
3835 // Verify texture format fails by default.
3836 glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, GL_UNSIGNED_BYTE, nullptr);
3837 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3838
3839 if (extensionRequestable(extName))
3840 {
3841 // Verify texture format is allowed once extension is enabled.
3842 glRequestExtensionANGLE(extName.c_str());
3843 EXPECT_TRUE(extensionEnabled(extName));
3844
3845 glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, GL_UNSIGNED_BYTE, nullptr);
3846 ASSERT_GL_NO_ERROR();
3847 }
3848}
3849
Geoff Lang86f81162017-10-30 15:10:45 -04003850// Test enabling various non-compressed texture format extensions
3851TEST_P(WebGLCompatibilityTest, EnableTextureFormatExtensions)
Bryan Bernhart (Intel Americas Inc)2a357412017-09-05 10:42:47 -07003852{
Geoff Lang2c5c41f2017-10-31 10:58:09 -04003853 ANGLE_SKIP_TEST_IF(IsOzone());
Bryan Bernhart (Intel Americas Inc)2a357412017-09-05 10:42:47 -07003854 ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
3855
3856 GLTexture texture;
3857 glBindTexture(GL_TEXTURE_2D, texture.get());
3858
3859 // Verify valid format is allowed.
3860 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3861 ASSERT_GL_NO_ERROR();
3862
3863 // Verify invalid format fails.
3864 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA32F, GL_UNSIGNED_BYTE, nullptr);
3865 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3866
3867 // Verify formats from enableable extensions.
Geoff Lang660b28c2017-10-30 12:58:56 -04003868 if (!IsOpenGLES())
Bryan Bernhart (Intel Americas Inc)2a357412017-09-05 10:42:47 -07003869 {
3870 validateTexImageExtensionFormat(GL_RED_EXT, "GL_EXT_texture_rg");
3871 }
3872
3873 validateTexImageExtensionFormat(GL_SRGB_EXT, "GL_EXT_texture_sRGB");
3874 validateTexImageExtensionFormat(GL_BGRA_EXT, "GL_EXT_texture_format_BGRA8888");
3875}
3876
Geoff Lang86f81162017-10-30 15:10:45 -04003877void WebGLCompatibilityTest::validateCompressedTexImageExtensionFormat(GLenum format,
3878 GLsizei width,
3879 GLsizei height,
3880 GLsizei blockSize,
3881 const std::string &extName,
3882 bool subImageAllowed)
3883{
3884 std::vector<GLubyte> data(blockSize, 0u);
3885
3886 GLTexture texture;
3887 glBindTexture(GL_TEXTURE_2D, texture.get());
3888
3889 // Verify texture format fails by default.
3890 glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, blockSize, data.data());
3891 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3892
3893 if (extensionRequestable(extName))
3894 {
3895 // Verify texture format is allowed once extension is enabled.
3896 glRequestExtensionANGLE(extName.c_str());
3897 EXPECT_TRUE(extensionEnabled(extName));
3898
3899 glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, blockSize, data.data());
3900 EXPECT_GL_NO_ERROR();
3901
3902 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, blockSize,
3903 data.data());
3904 if (subImageAllowed)
3905 {
3906 EXPECT_GL_NO_ERROR();
3907 }
3908 else
3909 {
3910 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3911 }
3912 }
3913}
3914
3915// Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGB_S3TC_DXT1_EXT
3916TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGB)
3917{
3918 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 8,
3919 "GL_EXT_texture_compression_dxt1", true);
3920}
3921
3922// Test enabling GL_EXT_texture_compression_dxt1 for GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
3923TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1RGBA)
3924{
3925 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 8,
3926 "GL_EXT_texture_compression_dxt1", true);
3927}
3928
3929// Test enabling GL_ANGLE_texture_compression_dxt3
3930TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT3)
3931{
3932 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, 4, 4, 16,
3933 "GL_ANGLE_texture_compression_dxt3", true);
3934}
3935
3936// Test enabling GL_ANGLE_texture_compression_dxt5
3937TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT5)
3938{
3939 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, 4, 4, 16,
3940 "GL_ANGLE_texture_compression_dxt5", true);
3941}
3942
3943// Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
3944TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1SRGB)
3945{
3946 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 4, 4, 8,
3947 "GL_EXT_texture_compression_s3tc_srgb", true);
3948}
3949
3950// Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
3951TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT1SRGBA)
3952{
3953 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 4, 4, 8,
3954 "GL_EXT_texture_compression_s3tc_srgb", true);
3955}
3956
3957// Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
3958TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT3SRGBA)
3959{
3960 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 4, 4, 16,
3961 "GL_EXT_texture_compression_s3tc_srgb", true);
3962}
3963
3964// Test enabling GL_EXT_texture_compression_s3tc_srgb for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
3965TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionDXT5SRGBA)
3966{
3967 validateCompressedTexImageExtensionFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 4, 4, 16,
3968 "GL_EXT_texture_compression_s3tc_srgb", true);
3969}
3970
3971// Test enabling GL_OES_compressed_ETC1_RGB8_texture
3972TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionETC1)
3973{
3974 validateCompressedTexImageExtensionFormat(GL_ETC1_RGB8_OES, 4, 4, 8,
3975 "GL_OES_compressed_ETC1_RGB8_texture", false);
3976}
3977
3978// Test enabling GL_ANGLE_lossy_etc_decode
3979TEST_P(WebGLCompatibilityTest, EnableCompressedTextureExtensionLossyDecode)
3980{
3981 validateCompressedTexImageExtensionFormat(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 4, 4, 8,
3982 "GL_ANGLE_lossy_etc_decode", true);
3983}
3984
Frank Henigmanfccbac22017-05-28 17:29:26 -04003985// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
3986// qualifiers.
3987TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
3988{
3989 const std::string vertexShader =
3990 "#version 300 es\n"
3991 "uniform Block { mediump vec4 val; };\n"
3992 "void main() { gl_Position = val; }\n";
3993 const std::string fragmentShader =
3994 "#version 300 es\n"
3995 "uniform Block { highp vec4 val; };\n"
3996 "out highp vec4 out_FragColor;\n"
3997 "void main() { out_FragColor = val; }\n";
3998
3999 GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
4000 ASSERT_NE(0u, vs);
4001 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
4002 ASSERT_NE(0u, fs);
4003
4004 GLuint program = glCreateProgram();
4005
4006 glAttachShader(program, vs);
4007 glDeleteShader(vs);
4008 glAttachShader(program, fs);
4009 glDeleteShader(fs);
4010
4011 glLinkProgram(program);
4012 GLint linkStatus;
4013 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
4014 ASSERT_EQ(0, linkStatus);
4015
4016 glDeleteProgram(program);
4017}
4018
Geoff Lang69df2422017-07-05 12:42:31 -04004019// Test no attribute vertex shaders
4020TEST_P(WebGL2CompatibilityTest, NoAttributeVertexShader)
4021{
4022 const std::string vertexShader =
4023 "#version 300 es\n"
4024 "void main()\n"
4025 "{\n"
4026 "\n"
4027 " ivec2 xy = ivec2(gl_VertexID % 2, (gl_VertexID / 2 + gl_VertexID / 3) % 2);\n"
4028 " gl_Position = vec4(vec2(xy) * 2. - 1., 0, 1);\n"
4029 "}";
4030 const std::string fragmentShader =
4031 "#version 300 es\n"
4032 "precision mediump float;\n"
4033 "out vec4 result;\n"
4034 "void main()\n"
4035 "{\n"
4036 " result = vec4(0, 1, 0, 1);\n"
4037 "}";
4038
4039 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
4040 glUseProgram(program);
4041
4042 glDrawArrays(GL_TRIANGLES, 0, 6);
4043 ASSERT_GL_NO_ERROR();
4044 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4045}
4046
Brandon Jonesed5b46f2017-07-21 08:39:17 -07004047// Tests bindAttribLocations for length limit
4048TEST_P(WebGL2CompatibilityTest, BindAttribLocationLimitation)
4049{
4050 constexpr int maxLocStringLength = 1024;
4051 const std::string tooLongString(maxLocStringLength + 1, '_');
4052
4053 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
4054
4055 EXPECT_GL_ERROR(GL_INVALID_VALUE);
4056}
4057
Geoff Langc287ea62016-09-16 14:46:51 -04004058// Use this to select which configurations (e.g. which renderer, which GLES major version) these
4059// tests should be run against.
4060ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
4061 ES2_D3D9(),
4062 ES2_D3D11(),
4063 ES3_D3D11(),
Geoff Langc287ea62016-09-16 14:46:51 -04004064 ES2_OPENGL(),
4065 ES3_OPENGL(),
4066 ES2_OPENGLES(),
4067 ES3_OPENGLES());
4068
Jamie Madill07be8bf2017-02-02 19:59:57 -05004069ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Geoff Langc287ea62016-09-16 14:46:51 -04004070} // namespace