blob: 426abc554ec91f23df691f190b288ca0f3360f9f [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
121 GLRenderbuffer rbo;
122 glBindRenderbuffer(GL_RENDERBUFFER, rbo.get());
123 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
124
125 GLFramebuffer fbo;
126 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
127 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo.get());
128
129 GLTexture texture;
130 glBindTexture(GL_TEXTURE_2D, texture.get());
131
132 if (internalFormat == format)
133 {
134 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, textureData);
135 }
136 else
137 {
138 if (getClientMajorVersion() >= 3)
139 {
140 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
141 }
142 else
143 {
144 ASSERT_TRUE(extensionEnabled("GL_EXT_texture_storage"));
145 glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
146 }
147 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, format, type, textureData);
148 }
149
150 if (!texturingEnabled)
151 {
152 // Depending on the entry point and client version, different errors may be generated
153 ASSERT_GLENUM_NE(GL_NO_ERROR, glGetError());
154
155 // Two errors may be generated in the glTexStorage + glTexSubImage case, clear the
156 // second error
157 glGetError();
158
159 return;
160 }
161 ASSERT_GL_NO_ERROR();
162
163 glUniform1i(glGetUniformLocation(samplingProgram.get(), "tex"), 0);
164 glUniform4fv(glGetUniformLocation(samplingProgram.get(), "subtractor"), 1, floatData);
165
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
168 drawQuad(samplingProgram.get(), "position", 0.5f, 1.0f, true);
169 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
170
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
172 drawQuad(samplingProgram.get(), "position", 0.5f, 1.0f, true);
173
174 if (linearSamplingEnabled)
175 {
176 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
177 }
178 else
179 {
180 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
181 }
182
183 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(),
184 0);
185 glBindTexture(GL_TEXTURE_2D, 0);
186 if (!renderingEnabled)
187 {
188 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
189 glCheckFramebufferStatus(GL_FRAMEBUFFER));
190 return;
191 }
192 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
193
194 const std::string renderingVs =
195 "attribute vec4 position;\n"
196 "void main()\n"
197 "{\n"
198 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
199 "}\n";
200
201 const std::string renderingFs =
202 "precision mediump float;\n"
203 "uniform vec4 writeValue;\n"
204 "void main()\n"
205 "{\n"
206 " gl_FragColor = writeValue;\n"
207 "}\n";
208
209 ANGLE_GL_PROGRAM(renderingProgram, renderingVs, renderingFs);
210 glUseProgram(renderingProgram.get());
211
212 glUniform4fv(glGetUniformLocation(renderingProgram.get(), "writeValue"), 1, floatData);
213
214 drawQuad(renderingProgram.get(), "position", 0.5f, 1.0f, true);
215
216 EXPECT_PIXEL_COLOR32F_NEAR(
217 0, 0, GLColor32F(floatData[0], floatData[1], floatData[2], floatData[3]), 1.0f);
218 }
219
Jamie Madillcad97ee2017-02-02 18:52:44 -0500220 // Called from RenderingFeedbackLoopWithDrawBuffersEXT.
221 void drawBuffersEXTFeedbackLoop(GLuint program,
222 const std::array<GLenum, 2> &drawBuffers,
223 GLenum expectedError);
224
Jamie Madill07be8bf2017-02-02 19:59:57 -0500225 // Called from RenderingFeedbackLoopWithDrawBuffers.
226 void drawBuffersFeedbackLoop(GLuint program,
227 const std::array<GLenum, 2> &drawBuffers,
228 GLenum expectedError);
229
Geoff Langc339c4e2016-11-29 10:37:36 -0500230 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
Geoff Langc287ea62016-09-16 14:46:51 -0400231};
232
Corentin Wallezfd456442016-12-21 17:57:00 -0500233class WebGL2CompatibilityTest : public WebGLCompatibilityTest
234{
235};
236
Geoff Langc287ea62016-09-16 14:46:51 -0400237// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
238// the GL extension should always be present
239TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
240{
241 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
242}
243
244// Verify that all extension entry points are available
245TEST_P(WebGLCompatibilityTest, EntryPoints)
246{
Geoff Langc339c4e2016-11-29 10:37:36 -0500247 if (extensionEnabled("GL_ANGLE_request_extension"))
Geoff Langc287ea62016-09-16 14:46:51 -0400248 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500249 EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -0400250 }
251}
252
253// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point. Make sure it is usable,
254// even in ES2 contexts.
255TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
256{
257 GLRenderbuffer renderbuffer;
258 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
259 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
260
261 GLFramebuffer framebuffer;
262 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
263 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
264 renderbuffer.get());
265
266 EXPECT_GL_NO_ERROR();
267}
268
269// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
270TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
271{
Geoff Langc339c4e2016-11-29 10:37:36 -0500272 glRequestExtensionANGLE("invalid_extension_string");
Geoff Langc287ea62016-09-16 14:46:51 -0400273 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
274}
275
276// Test enabling the GL_OES_element_index_uint extension
277TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
278{
279 if (getClientMajorVersion() != 2)
280 {
281 // This test only works on ES2 where uint indices are not available by default
282 return;
283 }
284
285 EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
286
287 GLBuffer indexBuffer;
288 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
289
290 GLuint data[] = {0, 1, 2, 1, 3, 2};
291 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
292
293 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
294 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
295 glUseProgram(program.get());
296
Jamie Madille7b96342017-06-23 15:06:08 -0400297 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
Geoff Langc287ea62016-09-16 14:46:51 -0400298 EXPECT_GL_ERROR(GL_INVALID_ENUM);
299
Geoff Langc339c4e2016-11-29 10:37:36 -0500300 if (extensionRequestable("GL_OES_element_index_uint"))
Geoff Langc287ea62016-09-16 14:46:51 -0400301 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500302 glRequestExtensionANGLE("GL_OES_element_index_uint");
Geoff Langc287ea62016-09-16 14:46:51 -0400303 EXPECT_GL_NO_ERROR();
304 EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
305
Jamie Madille7b96342017-06-23 15:06:08 -0400306 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
Geoff Langc287ea62016-09-16 14:46:51 -0400307 EXPECT_GL_NO_ERROR();
308 }
309}
310
Geoff Langff5c63e2017-04-12 15:26:54 -0400311// Test enabling the GL_OES_standard_derivatives extension
312TEST_P(WebGLCompatibilityTest, EnableExtensionStandardDerivitives)
313{
314 EXPECT_FALSE(extensionEnabled("GL_OES_standard_derivatives"));
315
316 const std::string source =
317 "#extension GL_OES_standard_derivatives : require\n"
318 "void main() { gl_FragColor = vec4(dFdx(vec2(1.0, 1.0)).x, 1, 0, 1); }\n";
319 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
320
321 if (extensionRequestable("GL_OES_standard_derivatives"))
322 {
323 glRequestExtensionANGLE("GL_OES_standard_derivatives");
324 EXPECT_GL_NO_ERROR();
325 EXPECT_TRUE(extensionEnabled("GL_OES_standard_derivatives"));
326
327 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
328 ASSERT_NE(0u, shader);
329 glDeleteShader(shader);
330 }
331}
332
333// Test enabling the GL_EXT_shader_texture_lod extension
334TEST_P(WebGLCompatibilityTest, EnableExtensionTextureLOD)
335{
336 EXPECT_FALSE(extensionEnabled("GL_EXT_shader_texture_lod"));
337
338 const std::string source =
339 "#extension GL_EXT_shader_texture_lod : require\n"
340 "uniform sampler2D u_texture;\n"
341 "void main() {\n"
342 " gl_FragColor = texture2DGradEXT(u_texture, vec2(0.0, 0.0), vec2(0.0, 0.0), vec2(0.0, "
343 "0.0));\n"
344 "}\n";
345 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
346
347 if (extensionRequestable("GL_EXT_shader_texture_lod"))
348 {
349 glRequestExtensionANGLE("GL_EXT_shader_texture_lod");
350 EXPECT_GL_NO_ERROR();
351 EXPECT_TRUE(extensionEnabled("GL_EXT_shader_texture_lod"));
352
353 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
354 ASSERT_NE(0u, shader);
355 glDeleteShader(shader);
356 }
357}
358
359// Test enabling the GL_EXT_frag_depth extension
360TEST_P(WebGLCompatibilityTest, EnableExtensionFragDepth)
361{
362 EXPECT_FALSE(extensionEnabled("GL_EXT_frag_depth"));
363
364 const std::string source =
365 "#extension GL_EXT_frag_depth : require\n"
366 "void main() {\n"
367 " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
368 " gl_FragDepthEXT = 1.0;\n"
369 "}\n";
370 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
371
372 if (extensionRequestable("GL_EXT_frag_depth"))
373 {
374 glRequestExtensionANGLE("GL_EXT_frag_depth");
375 EXPECT_GL_NO_ERROR();
376 EXPECT_TRUE(extensionEnabled("GL_EXT_frag_depth"));
377
378 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
379 ASSERT_NE(0u, shader);
380 glDeleteShader(shader);
381 }
382}
383
Geoff Langd7d526a2017-02-21 16:48:43 -0500384// Test enabling the GL_EXT_texture_filter_anisotropic extension
385TEST_P(WebGLCompatibilityTest, EnableExtensionTextureFilterAnisotropic)
386{
387 EXPECT_FALSE(extensionEnabled("GL_EXT_texture_filter_anisotropic"));
388
389 GLfloat maxAnisotropy = 0.0f;
390 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
391 EXPECT_GL_ERROR(GL_INVALID_ENUM);
392
393 GLTexture texture;
394 glBindTexture(GL_TEXTURE_2D, texture.get());
395 ASSERT_GL_NO_ERROR();
396
397 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
398 EXPECT_GL_ERROR(GL_INVALID_ENUM);
399
400 GLfloat currentAnisotropy = 0.0f;
401 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
402 EXPECT_GL_ERROR(GL_INVALID_ENUM);
403
404 if (extensionRequestable("GL_EXT_texture_filter_anisotropic"))
405 {
406 glRequestExtensionANGLE("GL_EXT_texture_filter_anisotropic");
407 EXPECT_GL_NO_ERROR();
408 EXPECT_TRUE(extensionEnabled("GL_EXT_texture_filter_anisotropic"));
409
410 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
411 ASSERT_GL_NO_ERROR();
412 EXPECT_GE(maxAnisotropy, 2.0f);
413
414 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
415 ASSERT_GL_NO_ERROR();
416 EXPECT_EQ(1.0f, currentAnisotropy);
417
418 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f);
419 ASSERT_GL_NO_ERROR();
420 }
421}
422
Bryan Bernhart87c182e2016-11-02 11:23:22 -0700423// Verify that shaders are of a compatible spec when the extension is enabled.
424TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
425{
426 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
427
428 // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
429 const std::string &vert =
430 "struct Foo {\n"
431 " int _webgl_bar;\n"
432 "};\n"
433 "void main()\n"
434 "{\n"
435 " Foo foo = Foo(1);\n"
436 "}";
437
438 // Default fragement shader.
439 const std::string &frag =
440 "void main()\n"
441 "{\n"
442 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n"
443 "}";
444
445 GLuint program = CompileProgram(vert, frag);
446 EXPECT_EQ(0u, program);
447 glDeleteProgram(program);
448}
449
Geoff Lang3fab7632017-09-26 15:45:54 -0400450// Test enabling the GL_NV_pixel_buffer_object extension
451TEST_P(WebGLCompatibilityTest, EnablePixelBufferObjectExtensions)
452{
453 EXPECT_FALSE(extensionEnabled("GL_NV_pixel_buffer_object"));
454 EXPECT_FALSE(extensionEnabled("GL_OES_mapbuffer"));
455 EXPECT_FALSE(extensionEnabled("GL_EXT_map_buffer_range"));
456
457 // These extensions become core in in ES3/WebGL2.
458 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
459
460 GLBuffer buffer;
461 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
462 EXPECT_GL_ERROR(GL_INVALID_ENUM);
463
464 if (extensionRequestable("GL_NV_pixel_buffer_object"))
465 {
466 glRequestExtensionANGLE("GL_NV_pixel_buffer_object");
467 EXPECT_GL_NO_ERROR();
468
469 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer);
470 EXPECT_GL_NO_ERROR();
471
472 glBufferData(GL_PIXEL_PACK_BUFFER, 4, nullptr, GL_STATIC_DRAW);
473 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
474 EXPECT_GL_NO_ERROR();
475 }
476}
477
478// Test enabling the GL_OES_mapbuffer and GL_EXT_map_buffer_range extensions
479TEST_P(WebGLCompatibilityTest, EnableMapBufferExtensions)
480{
481 EXPECT_FALSE(extensionEnabled("GL_OES_mapbuffer"));
482 EXPECT_FALSE(extensionEnabled("GL_EXT_map_buffer_range"));
483
484 // These extensions become core in in ES3/WebGL2.
485 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
486
487 GLBuffer buffer;
488 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
489 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4, nullptr, GL_STATIC_DRAW);
490
491 glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
492 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
493
494 glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
495 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
496
497 GLint access = 0;
498 glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
499 EXPECT_GL_ERROR(GL_INVALID_ENUM);
500
501 if (extensionRequestable("GL_OES_mapbuffer"))
502 {
503 glRequestExtensionANGLE("GL_OES_mapbuffer");
504 EXPECT_GL_NO_ERROR();
505
506 glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
507 glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
508 glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
509 EXPECT_GL_NO_ERROR();
510 }
511
512 if (extensionRequestable("GL_EXT_map_buffer_range"))
513 {
514 glRequestExtensionANGLE("GL_EXT_map_buffer_range");
515 EXPECT_GL_NO_ERROR();
516
517 glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, 0, 4, GL_MAP_WRITE_BIT);
518 glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);
519 glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_ACCESS_OES, &access);
520 EXPECT_GL_NO_ERROR();
521 }
522}
523
Geoff Lang8c7133c2017-09-26 17:31:10 -0400524// Test enabling the GL_OES_fbo_render_mipmap extension
525TEST_P(WebGLCompatibilityTest, EnableRenderMipmapExtension)
526{
527 EXPECT_FALSE(extensionEnabled("GL_OES_fbo_render_mipmap"));
528
529 // This extensions become core in in ES3/WebGL2.
530 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
531
532 GLTexture texture;
533 glBindTexture(GL_TEXTURE_2D, texture);
534 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
535 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
536
537 GLFramebuffer fbo;
538 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
539 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
540 EXPECT_GL_NO_ERROR();
541
542 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
543 EXPECT_GL_ERROR(GL_INVALID_VALUE);
544
545 if (extensionRequestable("GL_OES_fbo_render_mipmap"))
546 {
547 glRequestExtensionANGLE("GL_OES_fbo_render_mipmap");
548 EXPECT_GL_NO_ERROR();
549
550 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
551 EXPECT_GL_NO_ERROR();
552 }
553}
554
Geoff Lang50cac572017-09-26 17:37:43 -0400555// Test enabling the GL_EXT_blend_minmax extension
556TEST_P(WebGLCompatibilityTest, EnableBlendMinMaxExtension)
557{
558 EXPECT_FALSE(extensionEnabled("GL_EXT_blend_minmax"));
559
560 // This extensions become core in in ES3/WebGL2.
561 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
562
563 glBlendEquation(GL_MIN);
564 EXPECT_GL_ERROR(GL_INVALID_ENUM);
565
566 glBlendEquation(GL_MAX);
567 EXPECT_GL_ERROR(GL_INVALID_ENUM);
568
569 if (extensionRequestable("GL_EXT_blend_minmax"))
570 {
571 glRequestExtensionANGLE("GL_EXT_blend_minmax");
572 EXPECT_GL_NO_ERROR();
573
574 glBlendEquation(GL_MIN);
575 glBlendEquation(GL_MAX);
576 EXPECT_GL_NO_ERROR();
577 }
578}
579
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400580// Test enabling the query extensions
581TEST_P(WebGLCompatibilityTest, EnableQueryExtensions)
582{
583 EXPECT_FALSE(extensionEnabled("GL_EXT_occlusion_query_boolean"));
584 EXPECT_FALSE(extensionEnabled("GL_EXT_disjoint_timer_query"));
585 EXPECT_FALSE(extensionEnabled("GL_CHROMIUM_sync_query"));
586
587 // This extensions become core in in ES3/WebGL2.
588 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
589
590 GLQueryEXT badQuery;
591
592 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, badQuery);
593 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
594
595 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, badQuery);
596 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
597
598 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, badQuery);
599 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
600
601 glQueryCounterEXT(GL_TIMESTAMP_EXT, badQuery);
602 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
603
604 glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, badQuery);
605 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
606
607 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
608 {
609 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
610 EXPECT_GL_NO_ERROR();
611
612 GLQueryEXT query;
613 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
614 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
615 EXPECT_GL_NO_ERROR();
616 }
617
618 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
619 {
620 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
621 EXPECT_GL_NO_ERROR();
622
623 GLQueryEXT query1;
624 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query1);
625 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
626 EXPECT_GL_NO_ERROR();
627
628 GLQueryEXT query2;
629 glQueryCounterEXT(query2, GL_TIMESTAMP_EXT);
630 EXPECT_GL_NO_ERROR();
631 }
632
633 if (extensionRequestable("GL_CHROMIUM_sync_query"))
634 {
635 glRequestExtensionANGLE("GL_CHROMIUM_sync_query");
636 EXPECT_GL_NO_ERROR();
637
638 GLQueryEXT query;
639 glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query);
640 glEndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
641 EXPECT_GL_NO_ERROR();
642 }
643}
644
Geoff Lang488130e2017-09-27 13:53:11 -0400645// Test enabling the GL_ANGLE_framebuffer_multisample extension
646TEST_P(WebGLCompatibilityTest, EnableFramebufferMultisampleExtension)
647{
648 EXPECT_FALSE(extensionEnabled("GL_ANGLE_framebuffer_multisample"));
649
650 // This extensions become core in in ES3/WebGL2.
651 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
652
653 GLint maxSamples = 0;
654 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
655 EXPECT_GL_ERROR(GL_INVALID_ENUM);
656
657 GLRenderbuffer renderbuffer;
658 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
659 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 1, GL_RGBA4, 1, 1);
660 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
661
662 if (extensionRequestable("GL_ANGLE_framebuffer_multisample"))
663 {
664 glRequestExtensionANGLE("GL_ANGLE_framebuffer_multisample");
665 EXPECT_GL_NO_ERROR();
666
667 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
668 EXPECT_GL_NO_ERROR();
669
670 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, maxSamples, GL_RGBA4, 1, 1);
671 EXPECT_GL_NO_ERROR();
672 }
673}
674
Geoff Lang63c5a592017-09-27 14:08:16 -0400675// Test enabling the GL_ANGLE_instanced_arrays extension
676TEST_P(WebGLCompatibilityTest, EnableInstancedArraysExtension)
677{
678 EXPECT_FALSE(extensionEnabled("GL_ANGLE_instanced_arrays"));
679
680 // This extensions become core in in ES3/WebGL2.
681 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
682
683 GLint divisor = 0;
684 glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
685 EXPECT_GL_ERROR(GL_INVALID_ENUM);
686
687 glVertexAttribDivisorANGLE(0, 1);
688 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
689
690 if (extensionRequestable("GL_ANGLE_instanced_arrays"))
691 {
692 glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
693 EXPECT_GL_NO_ERROR();
694
695 glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor);
696 glVertexAttribDivisorANGLE(0, 1);
697 EXPECT_GL_NO_ERROR();
698 }
699}
700
Geoff Lang000dab82017-09-27 14:27:07 -0400701// Test enabling the GL_ANGLE_pack_reverse_row_order extension
702TEST_P(WebGLCompatibilityTest, EnablePackReverseRowOrderExtension)
703{
704 EXPECT_FALSE(extensionEnabled("GL_ANGLE_pack_reverse_row_order"));
705
706 GLint result = 0;
707 glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
708 EXPECT_GL_ERROR(GL_INVALID_ENUM);
709
710 glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
711 EXPECT_GL_ERROR(GL_INVALID_ENUM);
712
713 if (extensionRequestable("GL_ANGLE_pack_reverse_row_order"))
714 {
715 glRequestExtensionANGLE("GL_ANGLE_pack_reverse_row_order");
716 EXPECT_GL_NO_ERROR();
717
718 glGetIntegerv(GL_PACK_REVERSE_ROW_ORDER_ANGLE, &result);
719 glPixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, GL_TRUE);
720 EXPECT_GL_NO_ERROR();
721 }
722}
723
724// Test enabling the GL_EXT_unpack_subimage extension
725TEST_P(WebGLCompatibilityTest, EnablePackUnpackSubImageExtension)
726{
727 EXPECT_FALSE(extensionEnabled("GL_EXT_unpack_subimage"));
728
729 // This extensions become core in in ES3/WebGL2.
730 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
731
732 constexpr GLenum parameters[] = {
733 GL_UNPACK_ROW_LENGTH_EXT, GL_UNPACK_SKIP_ROWS_EXT, GL_UNPACK_SKIP_PIXELS_EXT,
734 };
735
736 for (GLenum param : parameters)
737 {
738 GLint resultI = 0;
739 glGetIntegerv(param, &resultI);
740 EXPECT_GL_ERROR(GL_INVALID_ENUM);
741
742 GLfloat resultF = 0.0f;
743 glGetFloatv(param, &resultF);
744 EXPECT_GL_ERROR(GL_INVALID_ENUM);
745
746 glPixelStorei(param, 0);
747 EXPECT_GL_ERROR(GL_INVALID_ENUM);
748 }
749
750 if (extensionRequestable("GL_EXT_unpack_subimage"))
751 {
752 glRequestExtensionANGLE("GL_EXT_unpack_subimage");
753 EXPECT_GL_NO_ERROR();
754
755 for (GLenum param : parameters)
756 {
757 GLint resultI = 0;
758 glGetIntegerv(param, &resultI);
759
760 GLfloat resultF = 0.0f;
761 glGetFloatv(param, &resultF);
762
763 glPixelStorei(param, 0);
764
765 EXPECT_GL_NO_ERROR();
766 }
767 }
768}
769
770// Test enabling the GL_NV_pack_subimage extension
771TEST_P(WebGLCompatibilityTest, EnablePackPackSubImageExtension)
772{
773 EXPECT_FALSE(extensionEnabled("GL_NV_pack_subimage"));
774
775 // This extensions become core in in ES3/WebGL2.
776 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
777
778 constexpr GLenum parameters[] = {
779 GL_PACK_ROW_LENGTH, GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS,
780 };
781
782 for (GLenum param : parameters)
783 {
784 GLint resultI = 0;
785 glGetIntegerv(param, &resultI);
786 EXPECT_GL_ERROR(GL_INVALID_ENUM);
787
788 GLfloat resultF = 0.0f;
789 glGetFloatv(param, &resultF);
790 EXPECT_GL_ERROR(GL_INVALID_ENUM);
791
792 glPixelStorei(param, 0);
793 EXPECT_GL_ERROR(GL_INVALID_ENUM);
794 }
795
796 if (extensionRequestable("GL_NV_pack_subimage"))
797 {
798 glRequestExtensionANGLE("GL_NV_pack_subimage");
799 EXPECT_GL_NO_ERROR();
800
801 for (GLenum param : parameters)
802 {
803 GLint resultI = 0;
804 glGetIntegerv(param, &resultI);
805
806 GLfloat resultF = 0.0f;
807 glGetFloatv(param, &resultF);
808
809 glPixelStorei(param, 0);
810
811 EXPECT_GL_NO_ERROR();
812 }
813 }
814}
815
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400816// Verify that the context generates the correct error when the framebuffer attachments are
817// different sizes
Corentin Wallezc3bc9842017-10-11 15:15:59 -0400818TEST_P(WebGLCompatibilityTest, FramebufferAttachmentSizeMismatch)
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400819{
820 GLFramebuffer fbo;
821 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
822
823 GLTexture textures[2];
824 glBindTexture(GL_TEXTURE_2D, textures[0]);
825 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
826 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
827
828 ASSERT_GL_NO_ERROR();
829 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
830
831 GLRenderbuffer renderbuffer;
832 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
833 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 3, 3);
834 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
835
836 ASSERT_GL_NO_ERROR();
837 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
838 glCheckFramebufferStatus(GL_FRAMEBUFFER));
839
840 if (extensionRequestable("GL_EXT_draw_buffers"))
841 {
842 glRequestExtensionANGLE("GL_EXT_draw_buffers");
843 EXPECT_GL_NO_ERROR();
844 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
845
846 glBindTexture(GL_TEXTURE_2D, textures[1]);
847 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
848 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
849 ASSERT_GL_NO_ERROR();
850
851 ASSERT_GL_NO_ERROR();
852 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
853 glCheckFramebufferStatus(GL_FRAMEBUFFER));
854
855 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
856
857 ASSERT_GL_NO_ERROR();
858 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
859
860 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
861
862 ASSERT_GL_NO_ERROR();
863 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
864 glCheckFramebufferStatus(GL_FRAMEBUFFER));
865 }
866}
867
Corentin Wallez327411e2016-12-09 11:09:17 -0500868// Test that client-side array buffers are forbidden in WebGL mode
869TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
870{
871 const std::string &vert =
872 "attribute vec3 a_pos;\n"
873 "void main()\n"
874 "{\n"
875 " gl_Position = vec4(a_pos, 1.0);\n"
876 "}\n";
877
878 const std::string &frag =
879 "precision highp float;\n"
880 "void main()\n"
881 "{\n"
882 " gl_FragColor = vec4(1.0);\n"
883 "}\n";
884
885 ANGLE_GL_PROGRAM(program, vert, frag);
886
887 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
888 ASSERT_NE(-1, posLocation);
889 glUseProgram(program.get());
890
891 const auto &vertices = GetQuadVertices();
Corentin Wallezfd456442016-12-21 17:57:00 -0500892 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
Corentin Wallez327411e2016-12-09 11:09:17 -0500893 glEnableVertexAttribArray(posLocation);
894
895 ASSERT_GL_NO_ERROR();
896 glDrawArrays(GL_TRIANGLES, 0, 6);
897 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
898}
899
900// Test that client-side element array buffers are forbidden in WebGL mode
901TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
902{
903 const std::string &vert =
904 "attribute vec3 a_pos;\n"
905 "void main()\n"
906 "{\n"
907 " gl_Position = vec4(a_pos, 1.0);\n"
908 "}\n";
909
910 const std::string &frag =
911 "precision highp float;\n"
912 "void main()\n"
913 "{\n"
914 " gl_FragColor = vec4(1.0);\n"
915 "}\n";
916
917 ANGLE_GL_PROGRAM(program, vert, frag);
918
919 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
920 ASSERT_NE(-1, posLocation);
921 glUseProgram(program.get());
922
923 const auto &vertices = GetQuadVertices();
924
925 GLBuffer vertexBuffer;
926 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
927 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
928 GL_STATIC_DRAW);
929
930 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
931 glEnableVertexAttribArray(posLocation);
932
Corentin Wallez327411e2016-12-09 11:09:17 -0500933 ASSERT_GL_NO_ERROR();
Corentin Wallezded1b5a2017-03-09 18:58:48 -0500934
935 // Use the pointer with value of 1 for indices instead of an actual pointer because WebGL also
936 // enforces that the top bit of indices must be 0 (i.e. offset >= 0) and would generate
937 // GL_INVALID_VALUE in that case. Using a null pointer gets caught by another check.
938 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void*>(intptr_t(1)));
Corentin Wallez327411e2016-12-09 11:09:17 -0500939 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
940}
941
Corentin Wallez672f7f32017-06-15 17:42:17 -0400942// Test that client-side array buffers are forbidden even if the program doesn't use the attribute
943TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBufferEvenNotUsedOnes)
944{
945 const std::string &vert =
946 "void main()\n"
947 "{\n"
948 " gl_Position = vec4(1.0);\n"
949 "}\n";
950
951 const std::string &frag =
952 "precision highp float;\n"
953 "void main()\n"
954 "{\n"
955 " gl_FragColor = vec4(1.0);\n"
956 "}\n";
957
958 ANGLE_GL_PROGRAM(program, vert, frag);
959
960 glUseProgram(program.get());
961
962 const auto &vertices = GetQuadVertices();
963 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
964 glEnableVertexAttribArray(0);
965
966 ASSERT_GL_NO_ERROR();
967 glDrawArrays(GL_TRIANGLES, 0, 6);
968 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
969}
970
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500971// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
972TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
973{
974 // Run the test in an FBO to make sure we have some stencil bits.
975 GLRenderbuffer renderbuffer;
976 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
977 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
978
979 GLFramebuffer framebuffer;
980 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
981 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
982 renderbuffer.get());
983
984 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
985 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
986 glUseProgram(program.get());
987 ASSERT_GL_NO_ERROR();
988
989 // Having ref and mask the same for front and back is valid.
990 glStencilMask(255);
991 glStencilFunc(GL_ALWAYS, 0, 255);
992 glDrawArrays(GL_TRIANGLES, 0, 6);
993 ASSERT_GL_NO_ERROR();
994
995 // Having a different front - back write mask generates an error.
996 glStencilMaskSeparate(GL_FRONT, 1);
997 glDrawArrays(GL_TRIANGLES, 0, 6);
998 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
999
1000 // Setting both write masks separately to the same value is valid.
1001 glStencilMaskSeparate(GL_BACK, 1);
1002 glDrawArrays(GL_TRIANGLES, 0, 6);
1003 ASSERT_GL_NO_ERROR();
1004
1005 // Having a different stencil front - back mask generates an error
1006 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
1007 glDrawArrays(GL_TRIANGLES, 0, 6);
1008 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1009
1010 // Setting both masks separately to the same value is valid.
1011 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
1012 glDrawArrays(GL_TRIANGLES, 0, 6);
1013 ASSERT_GL_NO_ERROR();
1014
1015 // Having a different stencil front - back reference generates an error
1016 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
1017 glDrawArrays(GL_TRIANGLES, 0, 6);
1018 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1019
1020 // Setting both references separately to the same value is valid.
1021 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
1022 glDrawArrays(GL_TRIANGLES, 0, 6);
1023 ASSERT_GL_NO_ERROR();
1024
1025 // Using different stencil funcs, everything being equal is valid.
1026 glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
1027 glDrawArrays(GL_TRIANGLES, 0, 6);
1028 ASSERT_GL_NO_ERROR();
1029}
1030
Corentin Wallez506fc9c2016-12-21 16:53:33 -05001031// Test that GL_FIXED is forbidden
1032TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
1033{
1034 GLBuffer buffer;
1035 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1036 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1037
1038 glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
1039 ASSERT_GL_NO_ERROR();
1040
1041 glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
1042 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1043}
1044
1045// Test the WebGL limit of 255 for the attribute stride
1046TEST_P(WebGLCompatibilityTest, MaxStride)
1047{
1048 GLBuffer buffer;
1049 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1050 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
1051
1052 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
1053 ASSERT_GL_NO_ERROR();
1054
1055 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
1056 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1057}
1058
Corentin Wallezfd456442016-12-21 17:57:00 -05001059// Test the checks for OOB reads in the vertex buffers, non-instanced version
1060TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
1061{
1062 const std::string &vert =
1063 "attribute float a_pos;\n"
1064 "void main()\n"
1065 "{\n"
1066 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1067 "}\n";
1068
1069 const std::string &frag =
1070 "precision highp float;\n"
1071 "void main()\n"
1072 "{\n"
1073 " gl_FragColor = vec4(1.0);\n"
1074 "}\n";
1075
1076 ANGLE_GL_PROGRAM(program, vert, frag);
Corentin Wallezfd456442016-12-21 17:57:00 -05001077 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1078 ASSERT_NE(-1, posLocation);
1079 glUseProgram(program.get());
1080
1081 GLBuffer buffer;
1082 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1083 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1084
1085 glEnableVertexAttribArray(posLocation);
1086
1087 const uint8_t* zeroOffset = nullptr;
1088
1089 // Test touching the last element is valid.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001090 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
Corentin Wallezfd456442016-12-21 17:57:00 -05001091 glDrawArrays(GL_POINTS, 0, 4);
1092 ASSERT_GL_NO_ERROR();
1093
1094 // Test touching the last element + 1 is invalid.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001095 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
Corentin Wallezfd456442016-12-21 17:57:00 -05001096 glDrawArrays(GL_POINTS, 0, 4);
1097 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1098
1099 // Test touching the last element is valid, using a stride.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001100 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
Corentin Wallezfd456442016-12-21 17:57:00 -05001101 glDrawArrays(GL_POINTS, 0, 4);
1102 ASSERT_GL_NO_ERROR();
1103
1104 // Test touching the last element + 1 is invalid, using a stride.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001105 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
Corentin Wallezfd456442016-12-21 17:57:00 -05001106 glDrawArrays(GL_POINTS, 0, 4);
1107 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1108
1109 // Test any offset is valid if no vertices are drawn.
Corentin Wallez91c8de82017-10-12 16:32:44 -04001110 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
Corentin Wallezfd456442016-12-21 17:57:00 -05001111 glDrawArrays(GL_POINTS, 0, 0);
1112 ASSERT_GL_NO_ERROR();
Corentin Wallez91c8de82017-10-12 16:32:44 -04001113
1114 // Test a case of overflow that could give a max vertex that's negative
1115 constexpr GLint kIntMax = std::numeric_limits<GLint>::max();
1116 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 0);
1117 glDrawArrays(GL_POINTS, kIntMax, kIntMax);
1118 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1119}
1120
1121// Test the checks for OOB reads in the vertex buffers, instanced version
1122TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
1123{
1124 const std::string &vert =
1125 "attribute float a_pos;\n"
1126 "attribute float a_w;\n"
1127 "void main()\n"
1128 "{\n"
1129 " gl_Position = vec4(a_pos, a_pos, a_pos, a_w);\n"
1130 "}\n";
1131
1132 const std::string &frag =
1133 "precision highp float;\n"
1134 "void main()\n"
1135 "{\n"
1136 " gl_FragColor = vec4(1.0);\n"
1137 "}\n";
1138
1139 ANGLE_GL_PROGRAM(program, vert, frag);
1140 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1141 GLint wLocation = glGetAttribLocation(program.get(), "a_w");
1142 ASSERT_NE(-1, posLocation);
1143 ASSERT_NE(-1, wLocation);
1144 glUseProgram(program.get());
1145
1146 GLBuffer buffer;
1147 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1148 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1149
1150 glEnableVertexAttribArray(posLocation);
1151 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1152 glVertexAttribDivisor(posLocation, 0);
1153
1154 glEnableVertexAttribArray(wLocation);
1155 glVertexAttribDivisor(wLocation, 1);
1156
1157 const uint8_t* zeroOffset = nullptr;
1158
1159 // Test touching the last element is valid.
1160 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1161 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1162 ASSERT_GL_NO_ERROR();
1163
1164 // Test touching the last element + 1 is invalid.
1165 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1166 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1167 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1168
1169 // Test touching the last element is valid, using a stride.
1170 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1171 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1172 ASSERT_GL_NO_ERROR();
1173
1174 // Test touching the last element + 1 is invalid, using a stride.
1175 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1176 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1177 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1178
1179 // Test any offset is valid if no vertices are drawn.
1180 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1181 glDrawArraysInstanced(GL_POINTS, 0, 0, 1);
1182 ASSERT_GL_NO_ERROR();
1183
1184 // Test any offset is valid if no primitives are drawn.
1185 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1186 glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
1187 ASSERT_GL_NO_ERROR();
1188}
1189
1190// Test the checks for OOB reads in the vertex buffers, ANGLE_instanced_arrays version
1191TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsInstancedANGLE)
1192{
1193 ANGLE_SKIP_TEST_IF(!extensionRequestable("GL_ANGLE_instanced_arrays"));
1194 glRequestExtensionANGLE("GL_ANGLE_instanced_arrays");
1195 EXPECT_GL_NO_ERROR();
1196
1197 const std::string &vert =
1198 "attribute float a_pos;\n"
1199 "attribute float a_w;\n"
1200 "void main()\n"
1201 "{\n"
1202 " gl_Position = vec4(a_pos, a_pos, a_pos, a_w);\n"
1203 "}\n";
1204
1205 const std::string &frag =
1206 "precision highp float;\n"
1207 "void main()\n"
1208 "{\n"
1209 " gl_FragColor = vec4(1.0);\n"
1210 "}\n";
1211
1212 ANGLE_GL_PROGRAM(program, vert, frag);
1213 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1214 GLint wLocation = glGetAttribLocation(program.get(), "a_w");
1215 ASSERT_NE(-1, posLocation);
1216 ASSERT_NE(-1, wLocation);
1217 glUseProgram(program.get());
1218
1219 GLBuffer buffer;
1220 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1221 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1222
1223 glEnableVertexAttribArray(posLocation);
1224 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1225 glVertexAttribDivisorANGLE(posLocation, 0);
1226
1227 glEnableVertexAttribArray(wLocation);
1228 glVertexAttribDivisorANGLE(wLocation, 1);
1229
1230 const uint8_t* zeroOffset = nullptr;
1231
1232 // Test touching the last element is valid.
1233 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1234 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1235 ASSERT_GL_NO_ERROR();
1236
1237 // Test touching the last element + 1 is invalid.
1238 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1239 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1240 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1241
1242 // Test touching the last element is valid, using a stride.
1243 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1244 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1245 ASSERT_GL_NO_ERROR();
1246
1247 // Test touching the last element + 1 is invalid, using a stride.
1248 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1249 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 4);
1250 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1251
1252 // Test any offset is valid if no vertices are drawn.
1253 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1254 glDrawArraysInstancedANGLE(GL_POINTS, 0, 0, 1);
1255 ASSERT_GL_NO_ERROR();
1256
1257 // Test any offset is valid if no primitives are drawn.
1258 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1259 glDrawArraysInstancedANGLE(GL_POINTS, 0, 1, 0);
1260 ASSERT_GL_NO_ERROR();
Corentin Wallezfd456442016-12-21 17:57:00 -05001261}
1262
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001263// Test the checks for OOB reads in the index buffer
1264TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
Geoff Lang5f319a42017-01-09 16:49:19 -05001265{
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001266 const std::string &vert =
1267 "attribute float a_pos;\n"
1268 "void main()\n"
1269 "{\n"
1270 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1271 "}\n";
Geoff Lang5f319a42017-01-09 16:49:19 -05001272
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001273 const std::string &frag =
1274 "precision highp float;\n"
1275 "void main()\n"
1276 "{\n"
1277 " gl_FragColor = vec4(1.0);\n"
1278 "}\n";
1279
1280 ANGLE_GL_PROGRAM(program, vert, frag);
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001281 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1282 ASSERT_NE(-1, posLocation);
1283 glUseProgram(program.get());
1284
1285 GLBuffer vertexBuffer;
1286 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1287 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1288
1289 glEnableVertexAttribArray(posLocation);
Corentin Wallez91c8de82017-10-12 16:32:44 -04001290 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001291
1292 const uint8_t *zeroOffset = nullptr;
1293 const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
1294
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001295 GLBuffer indexBuffer;
1296 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1297 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
Geoff Lang5f319a42017-01-09 16:49:19 -05001298 ASSERT_GL_NO_ERROR();
1299
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001300 // Test touching the last index is valid
1301 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
1302 ASSERT_GL_NO_ERROR();
Geoff Lang5f319a42017-01-09 16:49:19 -05001303
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001304 // Test touching the last + 1 element is invalid
1305 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
1306 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang5f319a42017-01-09 16:49:19 -05001307
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001308 // Test any offset if valid if count is zero
1309 glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
1310 ASSERT_GL_NO_ERROR();
Corentin Wallezfe9306a2017-02-01 17:41:05 -05001311
1312 // Test touching the first index is valid
1313 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
1314 ASSERT_GL_NO_ERROR();
1315
1316 // Test touching the first - 1 index is invalid
1317 // The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
1318 // the historic behavior of WebGL implementations
1319 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset - 1);
1320 EXPECT_GL_ERROR(GL_INVALID_VALUE);
Geoff Lang5f319a42017-01-09 16:49:19 -05001321}
1322
Corentin Wallez91c8de82017-10-12 16:32:44 -04001323// Test the checks for OOB in vertex buffers caused by indices, non-instanced version
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001324TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInVertexBuffer)
1325{
1326 const std::string &vert =
1327 "attribute float a_pos;\n"
1328 "void main()\n"
1329 "{\n"
1330 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1331 "}\n";
1332
1333 const std::string &frag =
1334 "precision highp float;\n"
1335 "void main()\n"
1336 "{\n"
1337 " gl_FragColor = vec4(1.0);\n"
1338 "}\n";
1339
1340 ANGLE_GL_PROGRAM(program, vert, frag);
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001341 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1342 ASSERT_NE(-1, posLocation);
1343 glUseProgram(program.get());
1344
1345 GLBuffer vertexBuffer;
1346 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1347 glBufferData(GL_ARRAY_BUFFER, 8, nullptr, GL_STATIC_DRAW);
1348
1349 glEnableVertexAttribArray(posLocation);
Corentin Wallez91c8de82017-10-12 16:32:44 -04001350 glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001351
1352 const uint8_t *zeroOffset = nullptr;
1353 const uint8_t testIndices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 255};
1354
Corentin Wallezc3bc9842017-10-11 15:15:59 -04001355 GLBuffer indexBuffer;
1356 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1357 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(testIndices), testIndices, GL_STATIC_DRAW);
1358 ASSERT_GL_NO_ERROR();
1359
1360 // Test touching the end of the vertex buffer is valid
1361 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 7);
1362 ASSERT_GL_NO_ERROR();
1363
1364 // Test touching just after the end of the vertex buffer is invalid
1365 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 8);
1366 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1367
1368 // Test touching the whole vertex buffer is valid
1369 glDrawElements(GL_POINTS, 8, GL_UNSIGNED_BYTE, zeroOffset + 0);
1370 ASSERT_GL_NO_ERROR();
1371
1372 // Test an index that would be negative
1373 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, zeroOffset + 9);
1374 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1375}
1376
Frank Henigman6137ddc2017-02-10 18:55:07 -05001377// Test depth range with 'near' more or less than 'far.'
1378TEST_P(WebGLCompatibilityTest, DepthRange)
1379{
1380 glDepthRangef(0, 1);
1381 ASSERT_GL_NO_ERROR();
1382
1383 glDepthRangef(.5, .5);
1384 ASSERT_GL_NO_ERROR();
1385
1386 glDepthRangef(1, 0);
1387 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1388}
1389
Frank Henigman146e8a12017-03-02 23:22:37 -05001390// Test all blend function combinations.
1391// In WebGL it is invalid to combine constant color with constant alpha.
1392TEST_P(WebGLCompatibilityTest, BlendWithConstantColor)
1393{
1394 constexpr GLenum srcFunc[] = {
1395 GL_ZERO,
1396 GL_ONE,
1397 GL_SRC_COLOR,
1398 GL_ONE_MINUS_SRC_COLOR,
1399 GL_DST_COLOR,
1400 GL_ONE_MINUS_DST_COLOR,
1401 GL_SRC_ALPHA,
1402 GL_ONE_MINUS_SRC_ALPHA,
1403 GL_DST_ALPHA,
1404 GL_ONE_MINUS_DST_ALPHA,
1405 GL_CONSTANT_COLOR,
1406 GL_ONE_MINUS_CONSTANT_COLOR,
1407 GL_CONSTANT_ALPHA,
1408 GL_ONE_MINUS_CONSTANT_ALPHA,
1409 GL_SRC_ALPHA_SATURATE,
1410 };
1411
1412 constexpr GLenum dstFunc[] = {
1413 GL_ZERO, GL_ONE,
1414 GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
1415 GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
1416 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1417 GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA,
1418 GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
1419 GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA,
1420 };
1421
1422 for (GLenum src : srcFunc)
1423 {
1424 for (GLenum dst : dstFunc)
1425 {
1426 glBlendFunc(src, dst);
1427 CheckBlendFunctions(src, dst);
1428 glBlendFuncSeparate(src, dst, GL_ONE, GL_ONE);
1429 CheckBlendFunctions(src, dst);
1430 }
1431 }
1432}
1433
Geoff Langfc32e8b2017-05-31 14:16:59 -04001434// Test that binding/querying uniforms and attributes with invalid names generates errors
1435TEST_P(WebGLCompatibilityTest, InvalidAttributeAndUniformNames)
1436{
1437 const std::string validAttribName =
1438 "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
1439 const std::string validUniformName =
1440 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
Geoff Langa71a98e2017-06-19 15:15:00 -04001441 std::vector<char> invalidSet = {'"', '$', '`', '@', '\''};
1442 if (getClientMajorVersion() < 3)
1443 {
1444 invalidSet.push_back('\\');
1445 }
Geoff Langfc32e8b2017-05-31 14:16:59 -04001446
1447 std::string vert = "attribute float ";
1448 vert += validAttribName;
1449 vert +=
1450 ";\n"
1451 "void main()\n"
1452 "{\n"
1453 " gl_Position = vec4(1.0);\n"
1454 "}\n";
1455
1456 std::string frag =
1457 "precision highp float;\n"
1458 "uniform vec4 ";
1459 frag += validUniformName;
Geoff Langcab92ee2017-07-19 17:32:07 -04001460 // Insert illegal characters into comments
Geoff Langfc32e8b2017-05-31 14:16:59 -04001461 frag +=
1462 ";\n"
Geoff Langcab92ee2017-07-19 17:32:07 -04001463 " // $ \" @ /*\n"
Geoff Langfc32e8b2017-05-31 14:16:59 -04001464 "void main()\n"
Geoff Langcab92ee2017-07-19 17:32:07 -04001465 "{/*\n"
1466 " ` @ $\n"
1467 " */gl_FragColor = vec4(1.0);\n"
Geoff Langfc32e8b2017-05-31 14:16:59 -04001468 "}\n";
1469
1470 ANGLE_GL_PROGRAM(program, vert, frag);
1471 EXPECT_GL_NO_ERROR();
1472
1473 for (char invalidChar : invalidSet)
1474 {
1475 std::string invalidName = validAttribName + invalidChar;
1476 glGetAttribLocation(program, invalidName.c_str());
1477 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1478 << "glGetAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1479
1480 glBindAttribLocation(program, 0, invalidName.c_str());
1481 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1482 << "glBindAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1483 }
1484
1485 for (char invalidChar : invalidSet)
1486 {
1487 std::string invalidName = validUniformName + invalidChar;
1488 glGetUniformLocation(program, invalidName.c_str());
1489 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1490 << "glGetUniformLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1491 }
1492
1493 for (char invalidChar : invalidSet)
1494 {
1495 std::string invalidAttribName = validAttribName + invalidChar;
1496 const char *invalidVert[] = {
1497 "attribute float ",
1498 invalidAttribName.c_str(),
1499 ";\n",
1500 "void main()\n",
1501 "{\n",
1502 " gl_Position = vec4(1.0);\n",
1503 "}\n",
1504 };
1505
1506 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1507 glShaderSource(shader, static_cast<GLsizei>(ArraySize(invalidVert)), invalidVert, nullptr);
1508 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1509 glDeleteShader(shader);
1510 }
1511}
1512
Geoff Langcab92ee2017-07-19 17:32:07 -04001513// Test that line continuation is handled correctly when valdiating shader source
1514TEST_P(WebGL2CompatibilityTest, ShaderSourceLineContinuation)
1515{
1516 const char *validVert =
1517 "#version 300 es\n"
1518 "precision mediump float;\n"
1519 "\n"
1520 "void main ()\n"
1521 "{\n"
1522 " float f\\\n"
1523 "oo = 1.0;\n"
1524 " gl_Position = vec4(foo);\n"
1525 "}\n";
1526
1527 const char *invalidVert =
1528 "#version 300 es\n"
1529 "precision mediump float;\n"
1530 "\n"
1531 "void main ()\n"
1532 "{\n"
1533 " float f\\$\n"
1534 "oo = 1.0;\n"
1535 " gl_Position = vec4(foo);\n"
1536 "}\n";
1537
1538 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1539 glShaderSource(shader, 1, &validVert, nullptr);
1540 EXPECT_GL_NO_ERROR();
1541 glShaderSource(shader, 1, &invalidVert, nullptr);
1542 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1543 glDeleteShader(shader);
1544}
1545
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001546// Tests bindAttribLocations for reserved prefixes and length limits
1547TEST_P(WebGLCompatibilityTest, BindAttribLocationLimitation)
1548{
1549 constexpr int maxLocStringLength = 256;
1550 const std::string tooLongString(maxLocStringLength + 1, '_');
1551
1552 glBindAttribLocation(0, 0, "_webgl_var");
1553
1554 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1555
1556 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
1557
1558 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1559}
1560
Corentin Wallez0dc97812017-06-22 14:38:44 -04001561// Test that having no attributes with a zero divisor is valid in WebGL2
Geoff Lang407d4e72017-04-12 14:54:11 -04001562TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
1563{
1564 const std::string &vert =
1565 "attribute float a_pos;\n"
1566 "void main()\n"
1567 "{\n"
1568 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1569 "}\n";
1570
1571 const std::string &frag =
1572 "precision highp float;\n"
1573 "void main()\n"
1574 "{\n"
1575 " gl_FragColor = vec4(1.0);\n"
1576 "}\n";
1577
1578 ANGLE_GL_PROGRAM(program, vert, frag);
1579
1580 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1581 ASSERT_NE(-1, posLocation);
1582
1583 glUseProgram(program.get());
1584
1585 GLBuffer buffer;
1586 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1587 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1588
1589 glEnableVertexAttribArray(posLocation);
1590 glVertexAttribDivisor(posLocation, 1);
1591
Geoff Lang407d4e72017-04-12 14:54:11 -04001592 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1593 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
Geoff Lang407d4e72017-04-12 14:54:11 -04001594 ASSERT_GL_NO_ERROR();
1595}
1596
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001597// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
1598TEST_P(WebGLCompatibilityTest, NPOT)
1599{
1600 EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
1601
1602 // Create a texture and set an NPOT mip 0, should always be acceptable.
1603 GLTexture texture;
1604 glBindTexture(GL_TEXTURE_2D, texture.get());
1605 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1606 ASSERT_GL_NO_ERROR();
1607
1608 // Try setting an NPOT mip 1 and verify the error if WebGL 1
1609 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1610 if (getClientMajorVersion() < 3)
1611 {
1612 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1613 }
1614 else
1615 {
1616 ASSERT_GL_NO_ERROR();
1617 }
1618
1619 if (extensionRequestable("GL_OES_texture_npot"))
1620 {
1621 glRequestExtensionANGLE("GL_OES_texture_npot");
1622 ASSERT_GL_NO_ERROR();
1623
1624 // Try again to set NPOT mip 1
1625 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1626 ASSERT_GL_NO_ERROR();
1627 }
1628}
1629
Jamie Madillcad97ee2017-02-02 18:52:44 -05001630template <typename T>
1631void FillTexture2D(GLuint texture,
1632 GLsizei width,
1633 GLsizei height,
1634 const T &onePixelData,
1635 GLint level,
1636 GLint internalFormat,
1637 GLenum format,
1638 GLenum type)
1639{
1640 std::vector<T> allPixelsData(width * height, onePixelData);
1641
1642 glBindTexture(GL_TEXTURE_2D, texture);
1643 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
1644 allPixelsData.data());
1645 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1646 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1647 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1648 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1649}
1650
Frank Henigman875bbba2017-02-08 16:38:17 -05001651// Test that unset gl_Position defaults to (0,0,0,0).
1652TEST_P(WebGLCompatibilityTest, DefaultPosition)
1653{
1654 // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
1655 // and green otherwise. The center of each quadrant will be red if and only if all
1656 // four corners are red.
1657 const std::string vertexShader =
1658 "attribute vec3 pos;\n"
1659 "varying vec4 color;\n"
1660 "void main() {\n"
1661 " if (gl_Position == vec4(0,0,0,0)) {\n"
1662 " color = vec4(1,0,0,1);\n"
1663 " } else {\n"
1664 " color = vec4(0,1,0,1);\n"
1665 " }\n"
1666 " gl_Position = vec4(pos,1);\n"
1667 "}\n";
1668
1669 const std::string fragmentShader =
1670 "precision mediump float;\n"
1671 "varying vec4 color;\n"
1672 "void main() {\n"
1673 " gl_FragColor = color;\n"
1674 "}\n";
1675
1676 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1677 drawQuad(program.get(), "pos", 0.0f, 1.0f, true);
1678 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1679 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1680 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1681 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1682}
1683
Jamie Madilla4595b82017-01-11 17:36:34 -05001684// Tests that a rendering feedback loop triggers a GL error under WebGL.
1685// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
1686TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
1687{
1688 const std::string vertexShader =
1689 "attribute vec4 a_position;\n"
1690 "varying vec2 v_texCoord;\n"
1691 "void main() {\n"
1692 " gl_Position = a_position;\n"
1693 " v_texCoord = (a_position.xy * 0.5) + 0.5;\n"
1694 "}\n";
1695
1696 const std::string fragmentShader =
1697 "precision mediump float;\n"
1698 "varying vec2 v_texCoord;\n"
1699 "uniform sampler2D u_texture;\n"
1700 "void main() {\n"
1701 " // Shader swizzles color channels so we can tell if the draw succeeded.\n"
1702 " gl_FragColor = texture2D(u_texture, v_texCoord).gbra;\n"
1703 "}\n";
1704
1705 GLTexture texture;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001706 FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001707
1708 ASSERT_GL_NO_ERROR();
1709
1710 GLFramebuffer framebuffer;
1711 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1712 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1713
1714 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1715
1716 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1717
1718 GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
1719 ASSERT_NE(-1, uniformLoc);
1720
1721 glUseProgram(program.get());
1722 glUniform1i(uniformLoc, 0);
1723 glDisable(GL_BLEND);
1724 glDisable(GL_DEPTH_TEST);
1725 ASSERT_GL_NO_ERROR();
1726
1727 // Drawing with a texture that is also bound to the current framebuffer should fail
1728 glBindTexture(GL_TEXTURE_2D, texture.get());
1729 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1730 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1731
1732 // Ensure that the texture contents did not change after the previous render
1733 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1734 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1735 ASSERT_GL_NO_ERROR();
1736 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1737
1738 // Drawing when texture is bound to an inactive uniform should succeed
1739 GLTexture texture2;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001740 FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001741
1742 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1743 glActiveTexture(GL_TEXTURE1);
1744 glBindTexture(GL_TEXTURE_2D, texture.get());
1745 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1746 ASSERT_GL_NO_ERROR();
1747 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1748}
1749
Bryan Bernhart58806562017-01-05 13:09:31 -08001750// Test for the max draw buffers and color attachments.
1751TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
1752{
1753 // This test only applies to ES2.
1754 if (getClientMajorVersion() != 2)
1755 {
1756 return;
1757 }
1758
1759 GLFramebuffer fbo[2];
1760 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
1761
1762 // Test that is valid when we bind with a single attachment point.
1763 GLTexture texture;
1764 glBindTexture(GL_TEXTURE_2D, texture.get());
1765 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1766 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1767 ASSERT_GL_NO_ERROR();
1768
1769 // Test that enabling the draw buffers extension will allow us to bind with a non-zero
1770 // attachment point.
1771 if (extensionRequestable("GL_EXT_draw_buffers"))
1772 {
1773 glRequestExtensionANGLE("GL_EXT_draw_buffers");
1774 EXPECT_GL_NO_ERROR();
1775 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
1776
1777 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
1778
1779 GLTexture texture2;
1780 glBindTexture(GL_TEXTURE_2D, texture2.get());
1781 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1782 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
1783 0);
1784 ASSERT_GL_NO_ERROR();
1785 }
1786}
1787
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001788// Test that the offset in the index buffer is forced to be a multiple of the element size
1789TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
1790{
1791 const std::string &vert =
1792 "attribute vec3 a_pos;\n"
1793 "void main()\n"
1794 "{\n"
1795 " gl_Position = vec4(a_pos, 1.0);\n"
1796 "}\n";
1797
1798 const std::string &frag =
1799 "precision highp float;\n"
1800 "void main()\n"
1801 "{\n"
1802 " gl_FragColor = vec4(1.0);\n"
1803 "}\n";
1804
1805 ANGLE_GL_PROGRAM(program, vert, frag);
1806
1807 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1808 ASSERT_NE(-1, posLocation);
1809 glUseProgram(program.get());
1810
1811 const auto &vertices = GetQuadVertices();
1812
1813 GLBuffer vertexBuffer;
1814 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1815 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1816 GL_STATIC_DRAW);
1817
1818 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1819 glEnableVertexAttribArray(posLocation);
1820
1821 GLBuffer indexBuffer;
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001822 const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0, 0};
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001823 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1824 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
1825
1826 ASSERT_GL_NO_ERROR();
1827
1828 const char *zeroIndices = nullptr;
1829
1830 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
1831 ASSERT_GL_NO_ERROR();
1832
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001833 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001834 ASSERT_GL_NO_ERROR();
1835
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001836 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices + 1);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001837 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1838}
1839
1840// Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
1841// size
1842TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
1843{
1844 const char *zeroOffset = nullptr;
1845
1846 // Base case, vector of two floats
1847 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
1848 ASSERT_GL_NO_ERROR();
1849
1850 // Test setting a non-multiple offset
1851 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
1852 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1853 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
1854 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1855 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
1856 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1857
1858 // Test setting a non-multiple stride
1859 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
1860 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1861 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
1862 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1863 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
1864 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1865}
1866
Jamie Madillcad97ee2017-02-02 18:52:44 -05001867void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
1868 const std::array<GLenum, 2> &drawBuffers,
1869 GLenum expectedError)
1870{
1871 glDrawBuffersEXT(2, drawBuffers.data());
1872
1873 // Make sure framebuffer is complete before feedback loop detection
1874 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1875
1876 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
1877
1878 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
1879 // it should be NO_ERROR"
1880 EXPECT_GL_ERROR(expectedError);
1881}
1882
1883// This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
1884// Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
1885TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
1886{
1887 const std::string vertexShader =
1888 "attribute vec4 aPosition;\n"
1889 "varying vec2 texCoord;\n"
1890 "void main() {\n"
1891 " gl_Position = aPosition;\n"
1892 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
1893 "}\n";
1894
1895 const std::string fragmentShader =
1896 "#extension GL_EXT_draw_buffers : require\n"
1897 "precision mediump float;\n"
1898 "uniform sampler2D tex;\n"
1899 "varying vec2 texCoord;\n"
1900 "void main() {\n"
1901 " gl_FragData[0] = texture2D(tex, texCoord);\n"
1902 " gl_FragData[1] = texture2D(tex, texCoord);\n"
1903 "}\n";
1904
1905 GLsizei width = 8;
1906 GLsizei height = 8;
1907
1908 // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
1909 // extension and gl_FragData semantics are changed to enforce indexing by zero always.
1910 // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
1911 if (/*!extensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
1912 {
1913 // No WEBGL_draw_buffers support -- this is legal.
1914 return;
1915 }
1916
1917 GLint maxDrawBuffers = 0;
1918 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1919
1920 if (maxDrawBuffers < 2)
1921 {
1922 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
1923 return;
1924 }
1925
1926 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1927 glUseProgram(program.get());
1928 glViewport(0, 0, width, height);
1929
1930 GLTexture tex0;
1931 GLTexture tex1;
1932 GLFramebuffer fbo;
1933 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1934 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1935 ASSERT_GL_NO_ERROR();
1936
1937 glBindTexture(GL_TEXTURE_2D, tex1.get());
1938 GLint texLoc = glGetUniformLocation(program.get(), "tex");
1939 ASSERT_NE(-1, texLoc);
1940 glUniform1i(texLoc, 0);
1941 ASSERT_GL_NO_ERROR();
1942
1943 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
1944 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
1945 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
1946 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
1947
1948 drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
1949 GL_INVALID_OPERATION);
1950 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
1951 GL_INVALID_OPERATION);
1952 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
1953}
1954
Jamie Madill07be8bf2017-02-02 19:59:57 -05001955// Test tests that texture copying feedback loops are properly rejected in WebGL.
1956// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
1957TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
1958{
1959 GLTexture texture;
1960 glBindTexture(GL_TEXTURE_2D, texture.get());
1961 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1962 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1963 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1964 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1965 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1966
1967 GLTexture texture2;
1968 glBindTexture(GL_TEXTURE_2D, texture2.get());
1969 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1970 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1971 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1972 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1973 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1974
1975 GLFramebuffer framebuffer;
1976 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1977 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1978
1979 // framebuffer should be FRAMEBUFFER_COMPLETE.
1980 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1981 ASSERT_GL_NO_ERROR();
1982
1983 // testing copyTexImage2D
1984
1985 // copyTexImage2D to same texture but different level
1986 glBindTexture(GL_TEXTURE_2D, texture.get());
1987 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
1988 EXPECT_GL_NO_ERROR();
1989
1990 // copyTexImage2D to same texture same level, invalid feedback loop
1991 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
1992 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1993
1994 // copyTexImage2D to different texture
1995 glBindTexture(GL_TEXTURE_2D, texture2.get());
1996 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
1997 EXPECT_GL_NO_ERROR();
1998
1999 // testing copyTexSubImage2D
2000
2001 // copyTexSubImage2D to same texture but different level
2002 glBindTexture(GL_TEXTURE_2D, texture.get());
2003 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
2004 EXPECT_GL_NO_ERROR();
2005
2006 // copyTexSubImage2D to same texture same level, invalid feedback loop
2007 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2008 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2009
2010 // copyTexSubImage2D to different texture
2011 glBindTexture(GL_TEXTURE_2D, texture2.get());
2012 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2013 EXPECT_GL_NO_ERROR();
2014}
2015
2016void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
2017 const std::array<GLenum, 2> &drawBuffers,
2018 GLenum expectedError)
2019{
2020 glDrawBuffers(2, drawBuffers.data());
2021
2022 // Make sure framebuffer is complete before feedback loop detection
2023 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2024
2025 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2026
2027 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2028 // it should be NO_ERROR"
2029 EXPECT_GL_ERROR(expectedError);
2030}
2031
Yuly Novikov817232e2017-02-22 18:36:10 -05002032// Tests invariance matching rules between built in varyings.
2033// Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
2034TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
2035{
2036 const std::string vertexShaderVariant =
2037 "varying vec4 v_varying;\n"
2038 "void main()\n"
2039 "{\n"
2040 " gl_PointSize = 1.0;\n"
2041 " gl_Position = v_varying;\n"
2042 "}";
2043 const std::string fragmentShaderInvariantGlFragCoord =
2044 "invariant gl_FragCoord;\n"
2045 "void main()\n"
2046 "{\n"
2047 " gl_FragColor = gl_FragCoord;\n"
2048 "}";
2049 const std::string fragmentShaderInvariantGlPointCoord =
2050 "invariant gl_PointCoord;\n"
2051 "void main()\n"
2052 "{\n"
2053 " gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);\n"
2054 "}";
2055
2056 GLuint program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlFragCoord);
2057 EXPECT_EQ(0u, program);
2058
2059 program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlPointCoord);
2060 EXPECT_EQ(0u, program);
2061}
2062
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002063// Tests global namespace conflicts between uniforms and attributes.
2064// Based on WebGL test conformance/glsl/misc/shaders-with-name-conflicts.html.
2065TEST_P(WebGLCompatibilityTest, GlobalNamesConflict)
2066{
2067 const std::string vertexShader =
2068 "attribute vec4 foo;\n"
2069 "void main()\n"
2070 "{\n"
2071 " gl_Position = foo;\n"
2072 "}";
2073 const std::string fragmentShader =
2074 "precision mediump float;\n"
2075 "uniform vec4 foo;\n"
2076 "void main()\n"
2077 "{\n"
2078 " gl_FragColor = foo;\n"
2079 "}";
2080
2081 GLuint program = CompileProgram(vertexShader, fragmentShader);
2082 EXPECT_EQ(0u, program);
2083}
2084
Geoff Lang966c9402017-04-18 12:38:27 -04002085// Test dimension and image size validation of compressed textures
2086TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
2087{
2088 if (extensionRequestable("GL_EXT_texture_compression_dxt1"))
2089 {
2090 glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
2091 }
2092
2093 if (!extensionEnabled("GL_EXT_texture_compression_dxt1"))
2094 {
2095 std::cout << "Test skipped because GL_EXT_texture_compression_dxt1 is not available."
2096 << std::endl;
2097 return;
2098 }
2099
2100 constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
2101
2102 GLTexture texture;
2103 glBindTexture(GL_TEXTURE_2D, texture);
2104
2105 // Regular case, verify that it works
2106 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2107 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2108 ASSERT_GL_NO_ERROR();
2109
2110 // Test various dimensions that are not valid
2111 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
2112 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2113 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2114
2115 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
2116 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2117 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2118
2119 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2120 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2121 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2122
2123 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2124 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2125 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2126
2127 // Test various image sizes that are not valid
2128 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2129 sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
2130 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2131
2132 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2133 sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
2134 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2135
2136 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
2137 CompressedImageDXT1);
2138 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2139
2140 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
2141 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2142 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2143
2144 // Fill a full mip chain and verify that it works
2145 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2146 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2147 glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2148 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2149 glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2150 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2151 ASSERT_GL_NO_ERROR();
2152
2153 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2154 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2155 ASSERT_GL_NO_ERROR();
2156
2157 // Test that non-block size sub-uploads are not valid for the 0 mip
2158 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2159 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2160 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2161
2162 // Test that non-block size sub-uploads are valid for if they fill the whole mip
2163 glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2164 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2165 glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2166 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2167 ASSERT_GL_NO_ERROR();
2168
2169 // Test that if the format miss-matches the texture, an error is generated
2170 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
2171 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2172 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2173}
2174
Geoff Lang677bb6f2017-04-05 12:40:40 -04002175TEST_P(WebGLCompatibilityTest, L32FTextures)
2176{
2177 constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f};
2178 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
2179
2180 for (auto extension : FloatingPointTextureExtensions)
2181 {
2182 if (strlen(extension) > 0 && extensionRequestable(extension))
2183 {
2184 glRequestExtensionANGLE(extension);
2185 ASSERT_GL_NO_ERROR();
2186 }
2187
2188 // Unsized L 32F
2189 {
2190 bool texture = extensionEnabled("GL_OES_texture_float");
2191 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2192 bool render = false;
2193 TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
2194 textureData, readPixelData);
2195 }
2196
2197 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2198 {
2199 // Sized L 32F
2200 bool texture = extensionEnabled("GL_OES_texture_float") &&
2201 extensionEnabled("GL_EXT_texture_storage");
2202 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2203 bool render = false;
2204 TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
2205 render, textureData, readPixelData);
2206 }
2207 }
2208}
2209
2210TEST_P(WebGLCompatibilityTest, A32FTextures)
2211{
2212 constexpr float textureData[] = {33.33f, 0.0f, 0.0f, 0.0f};
2213 constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
2214
2215 for (auto extension : FloatingPointTextureExtensions)
2216 {
2217 if (strlen(extension) > 0 && extensionRequestable(extension))
2218 {
2219 glRequestExtensionANGLE(extension);
2220 ASSERT_GL_NO_ERROR();
2221 }
2222
2223 // Unsized A 32F
2224 {
2225 bool texture = extensionEnabled("GL_OES_texture_float");
2226 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2227 bool render = false;
2228 TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
2229 textureData, readPixelData);
2230 }
2231
2232 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2233 {
2234 // Sized A 32F
2235 bool texture = extensionEnabled("GL_OES_texture_float") &&
2236 extensionEnabled("GL_EXT_texture_storage");
2237 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2238 bool render = false;
2239 TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
2240 textureData, readPixelData);
2241 }
2242 }
2243}
2244
2245TEST_P(WebGLCompatibilityTest, LA32FTextures)
2246{
2247 constexpr float textureData[] = {-0.21f, 15.1f, 0.0f, 0.0f};
2248 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
2249 textureData[1]};
2250
2251 for (auto extension : FloatingPointTextureExtensions)
2252 {
2253 if (strlen(extension) > 0 && extensionRequestable(extension))
2254 {
2255 glRequestExtensionANGLE(extension);
2256 ASSERT_GL_NO_ERROR();
2257 }
2258
2259 // Unsized LA 32F
2260 {
2261 bool texture = extensionEnabled("GL_OES_texture_float");
2262 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2263 bool render = false;
2264 TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
2265 filter, render, textureData, readPixelData);
2266 }
2267
2268 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2269 {
2270 // Sized LA 32F
2271 bool texture = extensionEnabled("GL_OES_texture_float") &&
2272 extensionEnabled("GL_EXT_texture_storage");
2273 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2274 bool render = false;
2275 TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
2276 filter, render, textureData, readPixelData);
2277 }
2278 }
2279}
2280
2281TEST_P(WebGLCompatibilityTest, R32FTextures)
2282{
2283 constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
2284
2285 for (auto extension : FloatingPointTextureExtensions)
2286 {
2287 if (strlen(extension) > 0 && extensionRequestable(extension))
2288 {
2289 glRequestExtensionANGLE(extension);
2290 ASSERT_GL_NO_ERROR();
2291 }
2292
2293 // Unsized R 32F
2294 {
2295 bool texture =
2296 extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg");
2297 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2298 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2299 TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
2300 }
2301
2302 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2303 {
2304 // Sized R 32F
2305 bool texture =
2306 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2307 extensionEnabled("GL_EXT_texture_rg") &&
2308 extensionEnabled("GL_EXT_texture_storage"));
2309 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2310 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2311 TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
2312 }
2313 }
2314}
2315
2316TEST_P(WebGLCompatibilityTest, RG32FTextures)
2317{
2318 constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
2319
2320 for (auto extension : FloatingPointTextureExtensions)
2321 {
2322 if (strlen(extension) > 0 && extensionRequestable(extension))
2323 {
2324 glRequestExtensionANGLE(extension);
2325 ASSERT_GL_NO_ERROR();
2326 }
2327
2328 // Unsized RG 32F
2329 {
2330 bool texture =
2331 (extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg"));
2332 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2333 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2334 TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
2335 }
2336
2337 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2338 {
2339 // Sized RG 32F
2340 bool texture =
2341 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2342 extensionEnabled("GL_EXT_texture_rg") &&
2343 extensionEnabled("GL_EXT_texture_storage"));
2344 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2345 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2346 TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
2347 }
2348 }
2349}
2350
2351TEST_P(WebGLCompatibilityTest, RGB32FTextures)
2352{
Geoff Lang40762ef2017-05-08 13:47:03 -04002353 if (IsLinux() && IsIntel())
2354 {
2355 std::cout << "Test skipped on Linux Intel." << std::endl;
2356 return;
2357 }
2358
Geoff Lang677bb6f2017-04-05 12:40:40 -04002359 constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
2360
2361 for (auto extension : FloatingPointTextureExtensions)
2362 {
2363 if (strlen(extension) > 0 && extensionRequestable(extension))
2364 {
2365 glRequestExtensionANGLE(extension);
2366 ASSERT_GL_NO_ERROR();
2367 }
2368
2369 // Unsized RGB 32F
2370 {
2371 bool texture = extensionEnabled("GL_OES_texture_float");
2372 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2373 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
2374 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
2375 }
2376
2377 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2378 {
2379 // Sized RGBA 32F
2380 bool texture =
2381 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2382 extensionEnabled("GL_EXT_texture_storage"));
2383 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2384 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
2385 TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
2386 data);
2387 }
2388 }
2389}
2390
2391TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
2392{
2393 constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2394
2395 for (auto extension : FloatingPointTextureExtensions)
2396 {
2397 if (strlen(extension) > 0 && extensionRequestable(extension))
2398 {
2399 glRequestExtensionANGLE(extension);
2400 ASSERT_GL_NO_ERROR();
2401 }
2402
2403 // Unsized RGBA 32F
2404 {
2405 bool texture = extensionEnabled("GL_OES_texture_float");
2406 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2407 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2408 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2409 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
2410 }
2411
2412 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2413 {
2414 // Sized RGBA 32F
2415 bool texture =
2416 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2417 extensionEnabled("GL_EXT_texture_storage"));
2418 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2419 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2420 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2421 TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
2422 data);
2423 }
2424 }
2425}
2426
2427TEST_P(WebGLCompatibilityTest, R16FTextures)
2428{
2429 constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
2430 const GLushort textureData[] = {
2431 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2432 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2433
2434 for (auto extension : FloatingPointTextureExtensions)
2435 {
2436 if (strlen(extension) > 0 && extensionRequestable(extension))
2437 {
2438 glRequestExtensionANGLE(extension);
2439 ASSERT_GL_NO_ERROR();
2440 }
2441
2442 // Unsized R 16F (OES)
2443 {
2444 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2445 extensionEnabled("GL_EXT_texture_rg");
2446 bool filter = getClientMajorVersion() >= 3 ||
2447 extensionEnabled("GL_OES_texture_half_float_linear");
2448 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2449 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
2450 textureData, readPixelsData);
2451 }
2452
2453 // Unsized R 16F
2454 {
2455 bool texture = false;
2456 bool filter = false;
2457 bool render = false;
2458 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2459 textureData, readPixelsData);
2460 }
2461
2462 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2463 {
2464 // Sized R 16F
2465 bool texture = getClientMajorVersion() >= 3;
2466 bool filter = getClientMajorVersion() >= 3 ||
2467 extensionEnabled("GL_OES_texture_half_float_linear");
2468 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2469 extensionEnabled("GL_EXT_color_buffer_float");
2470 TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2471 textureData, readPixelsData);
2472 }
2473 }
2474}
2475
2476TEST_P(WebGLCompatibilityTest, RG16FTextures)
2477{
2478 constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
2479 const GLushort textureData[] = {
2480 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2481 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2482
2483 for (auto extension : FloatingPointTextureExtensions)
2484 {
2485 if (strlen(extension) > 0 && extensionRequestable(extension))
2486 {
2487 glRequestExtensionANGLE(extension);
2488 ASSERT_GL_NO_ERROR();
2489 }
2490
2491 // Unsized RG 16F (OES)
2492 {
2493 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2494 extensionEnabled("GL_EXT_texture_rg");
2495 bool filter = getClientMajorVersion() >= 3 ||
2496 extensionEnabled("GL_OES_texture_half_float_linear");
2497 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") &&
2498 extensionEnabled("GL_EXT_texture_rg");
2499 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
2500 textureData, readPixelsData);
2501 }
2502
2503 // Unsized RG 16F
2504 {
2505 bool texture = false;
2506 bool filter = false;
2507 bool render = false;
2508 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2509 textureData, readPixelsData);
2510 }
2511
2512 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2513 {
2514 // Sized RG 16F
2515 bool texture = getClientMajorVersion() >= 3;
2516 bool filter = getClientMajorVersion() >= 3 ||
2517 extensionEnabled("GL_OES_texture_half_float_linear");
2518 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2519 extensionEnabled("GL_EXT_color_buffer_float");
2520 TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2521 textureData, readPixelsData);
2522 }
2523 }
2524}
2525
2526TEST_P(WebGLCompatibilityTest, RGB16FTextures)
2527{
Geoff Lang40762ef2017-05-08 13:47:03 -04002528 if (IsOzone() && IsIntel())
2529 {
2530 std::cout << "Test skipped on Intel Ozone." << std::endl;
2531 return;
2532 }
2533
Geoff Lang677bb6f2017-04-05 12:40:40 -04002534 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
2535 const GLushort textureData[] = {
2536 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2537 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2538
2539 for (auto extension : FloatingPointTextureExtensions)
2540 {
2541 if (strlen(extension) > 0 && extensionRequestable(extension))
2542 {
2543 glRequestExtensionANGLE(extension);
2544 ASSERT_GL_NO_ERROR();
2545 }
2546
2547 // Unsized RGB 16F (OES)
2548 {
2549 bool texture = extensionEnabled("GL_OES_texture_half_float");
2550 bool filter = getClientMajorVersion() >= 3 ||
2551 extensionEnabled("GL_OES_texture_half_float_linear");
2552 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2553 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
2554 textureData, readPixelsData);
2555 }
2556
2557 // Unsized RGB 16F
2558 {
2559 bool texture = false;
2560 bool filter = false;
2561 bool render = false;
2562 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2563 textureData, readPixelsData);
2564 }
2565
2566 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2567 {
2568 // Sized RGB 16F
2569 bool texture = getClientMajorVersion() >= 3;
2570 bool filter = getClientMajorVersion() >= 3 ||
2571 extensionEnabled("GL_OES_texture_half_float_linear");
2572 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2573 TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2574 textureData, readPixelsData);
2575 }
2576 }
2577}
2578
2579TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
2580{
Geoff Lang40762ef2017-05-08 13:47:03 -04002581 if (IsOzone() && IsIntel())
2582 {
2583 std::cout << "Test skipped on Intel Ozone." << std::endl;
2584 return;
2585 }
2586
Geoff Lang677bb6f2017-04-05 12:40:40 -04002587 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2588 const GLushort textureData[] = {
2589 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2590 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2591
2592 for (auto extension : FloatingPointTextureExtensions)
2593 {
2594 if (strlen(extension) > 0 && extensionRequestable(extension))
2595 {
2596 glRequestExtensionANGLE(extension);
2597 ASSERT_GL_NO_ERROR();
2598 }
2599
2600 // Unsized RGBA 16F (OES)
2601 {
2602 bool texture = extensionEnabled("GL_OES_texture_half_float");
2603 bool filter = getClientMajorVersion() >= 3 ||
2604 extensionEnabled("GL_OES_texture_half_float_linear");
2605 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2606 extensionEnabled("GL_EXT_color_buffer_float");
2607 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
2608 textureData, readPixelsData);
2609 }
2610
2611 // Unsized RGBA 16F
2612 {
2613 bool texture = false;
2614 bool filter = false;
2615 bool render = false;
2616 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2617 textureData, readPixelsData);
2618 }
2619
2620 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2621 {
2622 // Sized RGBA 16F
2623 bool texture = getClientMajorVersion() >= 3;
2624 bool filter = getClientMajorVersion() >= 3 ||
2625 extensionEnabled("GL_OES_texture_half_float_linear");
2626 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2627 extensionEnabled("GL_EXT_color_buffer_float");
2628 TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2629 textureData, readPixelsData);
2630 }
2631 }
2632}
2633
Geoff Lang6e898aa2017-06-02 11:17:26 -04002634// Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
2635// accepted by glTexImage2D
2636TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
2637{
2638 if (getClientMajorVersion() != 2)
2639 {
2640 std::cout << "Test skipped because it is only valid for WebGL1 contexts." << std::endl;
2641 return;
2642 }
2643
2644 if (!extensionRequestable("GL_OES_texture_float"))
2645 {
2646 std::cout << "Test skipped because GL_OES_texture_float is not requestable." << std::endl;
2647 return;
2648 }
2649 glRequestExtensionANGLE("GL_OES_texture_float");
2650 ASSERT_GL_NO_ERROR();
2651
2652 GLTexture texture;
2653 glBindTexture(GL_TEXTURE_2D, texture);
2654
2655 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2656 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2657
2658 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2659 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2660
2661 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
2662 {
2663 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
2664 ASSERT_GL_NO_ERROR();
2665
2666 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2667 EXPECT_GL_NO_ERROR();
2668 }
2669
2670 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
2671 {
2672 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
2673 ASSERT_GL_NO_ERROR();
2674
2675 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2676 EXPECT_GL_NO_ERROR();
2677 }
2678}
2679
Jamie Madill07be8bf2017-02-02 19:59:57 -05002680// This tests that rendering feedback loops works as expected with WebGL 2.
2681// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
2682TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
2683{
2684 const std::string vertexShader =
2685 "#version 300 es\n"
2686 "in vec4 aPosition;\n"
2687 "out vec2 texCoord;\n"
2688 "void main() {\n"
2689 " gl_Position = aPosition;\n"
2690 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2691 "}\n";
2692
2693 const std::string fragmentShader =
2694 "#version 300 es\n"
2695 "precision mediump float;\n"
2696 "uniform sampler2D tex;\n"
2697 "in vec2 texCoord;\n"
2698 "out vec4 oColor;\n"
2699 "void main() {\n"
2700 " oColor = texture(tex, texCoord);\n"
2701 "}\n";
2702
2703 GLsizei width = 8;
2704 GLsizei height = 8;
2705
2706 GLint maxDrawBuffers = 0;
2707 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2708 // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
2709 ASSERT_GE(maxDrawBuffers, 2);
2710
2711 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2712 glUseProgram(program.get());
2713 glViewport(0, 0, width, height);
2714
2715 GLTexture tex0;
2716 GLTexture tex1;
2717 GLFramebuffer fbo;
2718 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2719 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2720 ASSERT_GL_NO_ERROR();
2721
2722 glBindTexture(GL_TEXTURE_2D, tex1.get());
2723 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2724 ASSERT_NE(-1, texLoc);
2725 glUniform1i(texLoc, 0);
2726
2727 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2728 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2729 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2730 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
2731 ASSERT_GL_NO_ERROR();
2732
2733 drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
2734 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2735 GL_INVALID_OPERATION);
2736 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
2737}
2738
Jamie Madill1d37bc52017-02-02 19:59:58 -05002739// This test covers detection of rendering feedback loops between the FBO and a depth Texture.
2740// Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
2741TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
2742{
2743 const std::string vertexShader =
2744 "#version 300 es\n"
2745 "in vec4 aPosition;\n"
2746 "out vec2 texCoord;\n"
2747 "void main() {\n"
2748 " gl_Position = aPosition;\n"
2749 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2750 "}\n";
2751
2752 const std::string fragmentShader =
2753 "#version 300 es\n"
2754 "precision mediump float;\n"
2755 "uniform sampler2D tex;\n"
2756 "in vec2 texCoord;\n"
2757 "out vec4 oColor;\n"
2758 "void main() {\n"
2759 " oColor = texture(tex, texCoord);\n"
2760 "}\n";
2761
2762 GLsizei width = 8;
2763 GLsizei height = 8;
2764
2765 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2766 glUseProgram(program.get());
2767
2768 glViewport(0, 0, width, height);
2769
2770 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2771 glUniform1i(texLoc, 0);
2772
2773 // Create textures and allocate storage
2774 GLTexture tex0;
2775 GLTexture tex1;
2776 GLRenderbuffer rb;
2777 FillTexture2D(tex0.get(), width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2778 FillTexture2D(tex1.get(), width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
2779 GL_UNSIGNED_INT);
2780 glBindRenderbuffer(GL_RENDERBUFFER, rb.get());
2781 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
2782 ASSERT_GL_NO_ERROR();
2783
2784 GLFramebuffer fbo;
2785 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2786 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2787
2788 // Test rendering and sampling feedback loop for depth buffer
2789 glBindTexture(GL_TEXTURE_2D, tex1.get());
2790 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1.get(), 0);
2791 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2792
2793 // The same image is used as depth buffer during rendering.
2794 glEnable(GL_DEPTH_TEST);
2795 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2796 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2797
2798 // The same image is used as depth buffer. But depth mask is false.
2799 glDepthMask(GL_FALSE);
2800 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2801 EXPECT_GL_NO_ERROR();
2802
2803 // The same image is used as depth buffer. But depth test is not enabled during rendering.
2804 glDepthMask(GL_TRUE);
2805 glDisable(GL_DEPTH_TEST);
2806 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2807 EXPECT_GL_NO_ERROR();
2808
2809 // Test rendering and sampling feedback loop for stencil buffer
2810 glBindTexture(GL_RENDERBUFFER, rb.get());
2811 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
2812 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb.get());
2813 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2814 constexpr GLint stencilClearValue = 0x40;
2815 glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
2816
2817 // The same image is used as stencil buffer during rendering.
2818 glEnable(GL_STENCIL_TEST);
2819 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2820 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2821
2822 // The same image is used as stencil buffer. But stencil mask is zero.
2823 glStencilMask(0x0);
2824 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2825 EXPECT_GL_NO_ERROR();
2826
2827 // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
2828 glStencilMask(0xffff);
2829 glDisable(GL_STENCIL_TEST);
2830 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2831 EXPECT_GL_NO_ERROR();
2832}
2833
Jamie Madillfd3dd432017-02-02 19:59:59 -05002834// The source and the target for CopyTexSubImage3D are the same 3D texture.
2835// But the level of the 3D texture != the level of the read attachment.
2836TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
2837{
2838 GLTexture texture;
2839 GLFramebuffer framebuffer;
2840
2841 glBindTexture(GL_TEXTURE_3D, texture.get());
2842 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2843
2844 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2845 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2846 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
2847 ASSERT_GL_NO_ERROR();
2848
2849 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2850 EXPECT_GL_NO_ERROR();
2851}
2852
2853// The source and the target for CopyTexSubImage3D are the same 3D texture.
2854// But the zoffset of the 3D texture != the layer of the read attachment.
2855TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
2856{
2857 GLTexture texture;
2858 GLFramebuffer framebuffer;
2859
2860 glBindTexture(GL_TEXTURE_3D, texture.get());
2861 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2862
2863 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2864 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 1);
2865 ASSERT_GL_NO_ERROR();
2866
2867 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
2868 EXPECT_GL_NO_ERROR();
2869}
2870
2871// The source and the target for CopyTexSubImage3D are the same 3D texture.
2872// And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
2873TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
2874{
2875 GLTexture texture;
2876 GLFramebuffer framebuffer;
2877
2878 glBindTexture(GL_TEXTURE_3D, texture.get());
2879 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2880
2881 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2882 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2883 glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2884 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 1, 0);
2885 ASSERT_GL_NO_ERROR();
2886
2887 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2888 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2889}
2890
Corentin Wallez59c41592017-07-11 13:19:54 -04002891// Verify that errors are generated when there isn't a defined conversion between the clear type and
2892// the buffer type.
Geoff Lang76e65652017-03-27 14:58:02 -04002893TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
2894{
2895 if (IsD3D11())
2896 {
2897 std::cout << "Test skipped because it generates D3D11 runtime warnings." << std::endl;
2898 return;
2899 }
2900
2901 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
2902 constexpr int clearInt[] = {0, 0, 0, 0};
2903 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
2904
2905 GLTexture texture;
2906 GLFramebuffer framebuffer;
2907
2908 glBindTexture(GL_TEXTURE_2D, texture.get());
2909 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2910
2911 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2912 ASSERT_GL_NO_ERROR();
2913
2914 // Unsigned integer buffer
2915 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
2916 ASSERT_GL_NO_ERROR();
2917
2918 glClearBufferfv(GL_COLOR, 0, clearFloat);
2919 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2920
2921 glClearBufferiv(GL_COLOR, 0, clearInt);
2922 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2923
2924 glClearBufferuiv(GL_COLOR, 0, clearUint);
2925 EXPECT_GL_NO_ERROR();
2926
2927 glClear(GL_COLOR_BUFFER_BIT);
2928 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2929
2930 // Integer buffer
2931 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
2932 ASSERT_GL_NO_ERROR();
2933
2934 glClearBufferfv(GL_COLOR, 0, clearFloat);
2935 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2936
2937 glClearBufferiv(GL_COLOR, 0, clearInt);
2938 EXPECT_GL_NO_ERROR();
2939
2940 glClearBufferuiv(GL_COLOR, 0, clearUint);
2941 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2942
2943 glClear(GL_COLOR_BUFFER_BIT);
2944 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2945
2946 // Float buffer
Geoff Lang677bb6f2017-04-05 12:40:40 -04002947 if (extensionRequestable("GL_EXT_color_buffer_float"))
2948 {
2949 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
2950 }
Geoff Lang76e65652017-03-27 14:58:02 -04002951
Geoff Lang677bb6f2017-04-05 12:40:40 -04002952 if (extensionEnabled("GL_EXT_color_buffer_float"))
2953 {
2954 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2955 ASSERT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002956
Geoff Lang677bb6f2017-04-05 12:40:40 -04002957 glClearBufferfv(GL_COLOR, 0, clearFloat);
2958 EXPECT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002959
Geoff Lang677bb6f2017-04-05 12:40:40 -04002960 glClearBufferiv(GL_COLOR, 0, clearInt);
2961 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang76e65652017-03-27 14:58:02 -04002962
Geoff Lang677bb6f2017-04-05 12:40:40 -04002963 glClearBufferuiv(GL_COLOR, 0, clearUint);
2964 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2965
2966 glClear(GL_COLOR_BUFFER_BIT);
2967 EXPECT_GL_NO_ERROR();
2968 }
Geoff Lang76e65652017-03-27 14:58:02 -04002969
2970 // Normalized uint buffer
2971 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2972 ASSERT_GL_NO_ERROR();
2973
2974 glClearBufferfv(GL_COLOR, 0, clearFloat);
2975 EXPECT_GL_NO_ERROR();
2976
2977 glClearBufferiv(GL_COLOR, 0, clearInt);
2978 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2979
2980 glClearBufferuiv(GL_COLOR, 0, clearUint);
2981 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2982
2983 glClear(GL_COLOR_BUFFER_BIT);
2984 EXPECT_GL_NO_ERROR();
2985}
2986
Corentin Wallez59c41592017-07-11 13:19:54 -04002987// Test the interaction of WebGL compatibility clears with default framebuffers
2988TEST_P(WebGL2CompatibilityTest, ClearBufferDefaultFramebuffer)
2989{
2990 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
2991 constexpr int clearInt[] = {0, 0, 0, 0};
2992 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
2993
2994 // glClear works as usual, this is also a regression test for a bug where we
2995 // iterated on maxDrawBuffers for default framebuffers, triggering an assert
2996 glClear(GL_COLOR_BUFFER_BIT);
2997 EXPECT_GL_NO_ERROR();
2998
2999 // Default framebuffers are normalized uints, so only glClearBufferfv works.
3000 glClearBufferfv(GL_COLOR, 0, clearFloat);
3001 EXPECT_GL_NO_ERROR();
3002
3003 glClearBufferiv(GL_COLOR, 0, clearInt);
3004 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3005
3006 glClearBufferuiv(GL_COLOR, 0, clearUint);
3007 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3008}
3009
Geoff Lange4915782017-04-12 15:19:07 -04003010// Verify that errors are generate when trying to blit from an image to itself
3011TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
3012{
3013 GLTexture textures[2];
3014 glBindTexture(GL_TEXTURE_2D, textures[0]);
3015 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
3016 glBindTexture(GL_TEXTURE_2D, textures[1]);
3017 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
3018
3019 GLRenderbuffer renderbuffers[2];
3020 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
3021 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
3022 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
3023 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
3024
3025 GLFramebuffer framebuffers[2];
3026 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
3027 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
3028
3029 ASSERT_GL_NO_ERROR();
3030
3031 // Same texture
3032 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3033 0);
3034 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3035 0);
3036 ASSERT_GL_NO_ERROR();
3037 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3038 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3039
3040 // Same textures but different renderbuffers
3041 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3042 renderbuffers[0]);
3043 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3044 renderbuffers[1]);
3045 ASSERT_GL_NO_ERROR();
3046 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
3047 ASSERT_GL_NO_ERROR();
3048 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3049 GL_NEAREST);
3050 ASSERT_GL_NO_ERROR();
3051 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
3052 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3053 GL_NEAREST);
3054 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3055
3056 // Same renderbuffers but different textures
3057 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3058 0);
3059 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
3060 0);
3061 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3062 renderbuffers[0]);
3063 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3064 renderbuffers[0]);
3065 ASSERT_GL_NO_ERROR();
3066 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3067 ASSERT_GL_NO_ERROR();
3068 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3069 GL_NEAREST);
3070 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3071 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
3072 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3073 GL_NEAREST);
3074 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3075}
3076
Geoff Lange0cff192017-05-30 13:04:56 -04003077// Verify that errors are generated when the fragment shader output doesn't match the bound color
3078// buffer types
3079TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
3080{
3081 const std::string vertexShader =
3082 "#version 300 es\n"
3083 "void main() {\n"
3084 " gl_Position = vec4(0, 0, 0, 1);\n"
3085 "}\n";
3086
3087 const std::string fragmentShader =
3088 "#version 300 es\n"
3089 "precision mediump float;\n"
3090 "layout(location = 0) out vec4 floatOutput;\n"
3091 "layout(location = 1) out uvec4 uintOutput;\n"
3092 "layout(location = 2) out ivec4 intOutput;\n"
3093 "void main() {\n"
3094 " floatOutput = vec4(0, 0, 0, 1);\n"
3095 " uintOutput = uvec4(0, 0, 0, 1);\n"
3096 " intOutput = ivec4(0, 0, 0, 1);\n"
3097 "}\n";
3098
3099 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3100 glUseProgram(program.get());
3101
3102 GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
3103 GLuint uintLocation = glGetFragDataLocation(program, "uintOutput");
3104 GLuint intLocation = glGetFragDataLocation(program, "intOutput");
3105
3106 GLFramebuffer fbo;
3107 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3108
3109 GLRenderbuffer floatRenderbuffer;
3110 glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
3111 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
3112 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
3113 floatRenderbuffer);
3114
3115 GLRenderbuffer uintRenderbuffer;
3116 glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
3117 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
3118 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3119 uintRenderbuffer);
3120
3121 GLRenderbuffer intRenderbuffer;
3122 glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
3123 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
3124 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3125 intRenderbuffer);
3126
3127 ASSERT_GL_NO_ERROR();
3128
3129 GLint maxDrawBuffers = 0;
3130 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3131 std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
3132 drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
3133 drawBuffers[uintLocation] = GL_COLOR_ATTACHMENT0 + uintLocation;
3134 drawBuffers[intLocation] = GL_COLOR_ATTACHMENT0 + intLocation;
3135
3136 glDrawBuffers(maxDrawBuffers, drawBuffers.data());
3137
3138 // Check that the correct case generates no errors
3139 glDrawArrays(GL_TRIANGLES, 0, 6);
3140 EXPECT_GL_NO_ERROR();
3141
3142 // Unbind some buffers and verify that there are still no errors
3143 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3144 0);
3145 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3146 0);
3147 glDrawArrays(GL_TRIANGLES, 0, 6);
3148 EXPECT_GL_NO_ERROR();
3149
3150 // Swap the int and uint buffers to and verify that an error is generated
3151 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3152 intRenderbuffer);
3153 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3154 uintRenderbuffer);
3155 glDrawArrays(GL_TRIANGLES, 0, 6);
3156 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3157
3158 // Swap the float and uint buffers to and verify that an error is generated
3159 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3160 floatRenderbuffer);
3161 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
3162 uintRenderbuffer);
3163 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3164 intRenderbuffer);
3165 glDrawArrays(GL_TRIANGLES, 0, 6);
3166 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3167}
3168
Geoff Lang9ab5b822017-05-30 16:19:23 -04003169// Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
3170// types
Corentin Wallezc3bc9842017-10-11 15:15:59 -04003171TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMismatch)
Geoff Lang9ab5b822017-05-30 16:19:23 -04003172{
3173 const std::string vertexShader =
3174 "#version 300 es\n"
3175 "in vec4 floatInput;\n"
3176 "in uvec4 uintInput;\n"
3177 "in ivec4 intInput;\n"
3178 "void main() {\n"
3179 " gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);\n"
3180 "}\n";
3181
3182 const std::string fragmentShader =
3183 "#version 300 es\n"
3184 "precision mediump float;\n"
3185 "out vec4 outputColor;\n"
3186 "void main() {\n"
3187 " outputColor = vec4(0, 0, 0, 1);"
3188 "}\n";
3189
3190 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3191 glUseProgram(program.get());
3192
3193 GLint floatLocation = glGetAttribLocation(program, "floatInput");
3194 GLint uintLocation = glGetAttribLocation(program, "uintInput");
3195 GLint intLocation = glGetAttribLocation(program, "intInput");
3196
3197 // Default attributes are of float types
3198 glDrawArrays(GL_TRIANGLES, 0, 6);
3199 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3200
3201 // Set the default attributes to the correct types, should succeed
3202 glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
3203 glVertexAttribI4i(intLocation, 0, 0, 0, 1);
3204 glDrawArrays(GL_TRIANGLES, 0, 6);
3205 EXPECT_GL_NO_ERROR();
3206
3207 // Change the default float attribute to an integer, should fail
3208 glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
3209 glDrawArrays(GL_TRIANGLES, 0, 6);
3210 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3211
3212 // Use a buffer for some attributes
3213 GLBuffer buffer;
3214 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3215 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
3216 glEnableVertexAttribArray(floatLocation);
3217 glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
3218 glDrawArrays(GL_TRIANGLES, 0, 6);
3219 EXPECT_GL_NO_ERROR();
3220
3221 // Use a float pointer attrib for a uint input
3222 glEnableVertexAttribArray(uintLocation);
3223 glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
3224 glDrawArrays(GL_TRIANGLES, 0, 6);
3225 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3226
3227 // Use a uint pointer for the uint input
3228 glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
3229 glDrawArrays(GL_TRIANGLES, 0, 6);
3230 EXPECT_GL_NO_ERROR();
3231}
3232
Corentin Walleze7557742017-06-01 13:09:57 -04003233// Tests the WebGL removal of undefined behavior when attachments aren't written to.
3234TEST_P(WebGLCompatibilityTest, DrawBuffers)
3235{
Corentin Walleze7557742017-06-01 13:09:57 -04003236 // Make sure we can use at least 4 attachments for the tests.
3237 bool useEXT = false;
3238 if (getClientMajorVersion() < 3)
3239 {
3240 if (!extensionRequestable("GL_EXT_draw_buffers"))
3241 {
3242 std::cout << "Test skipped because draw buffers are not available" << std::endl;
3243 return;
3244 }
3245
3246 glRequestExtensionANGLE("GL_EXT_draw_buffers");
3247 useEXT = true;
3248 EXPECT_GL_NO_ERROR();
3249 }
3250
3251 GLint maxDrawBuffers = 0;
3252 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3253 if (maxDrawBuffers < 4)
3254 {
3255 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
3256 return;
3257 }
3258
3259 // Clears all the renderbuffers to red.
3260 auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
3261 GLFramebuffer clearFBO;
3262 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, clearFBO);
3263
3264 glClearColor(1, 0, 0, 1);
3265 for (int i = 0; i < 4; ++i)
3266 {
3267 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
3268 renderbuffers[i]);
3269 glClear(GL_COLOR_BUFFER_BIT);
3270 }
3271 ASSERT_GL_NO_ERROR();
3272 };
3273
3274 // Checks that the renderbuffers specified by mask have the correct color
3275 auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
3276 GLFramebuffer readFBO;
3277 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
3278
3279 for (int i = 0; i < 4; ++i)
3280 {
3281 if (mask & (1 << i))
3282 {
3283 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3284 GL_RENDERBUFFER, renderbuffers[i]);
3285 EXPECT_PIXEL_COLOR_EQ(0, 0, color);
3286 }
3287 }
3288 ASSERT_GL_NO_ERROR();
3289 };
3290
3291 // Depending on whether we are using the extension or ES3, a different entrypoint must be called
3292 auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
3293 if (useEXT)
3294 {
3295 glDrawBuffersEXT(numBuffers, buffers);
3296 }
3297 else
3298 {
3299 glDrawBuffers(numBuffers, buffers);
3300 }
3301 };
3302
3303 // Initialized the test framebuffer
3304 GLFramebuffer drawFBO;
3305 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3306
3307 GLRenderbuffer renderbuffers[4];
3308 for (int i = 0; i < 4; ++i)
3309 {
3310 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
3311 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
3312 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
3313 renderbuffers[i]);
3314 }
3315
3316 ASSERT_GL_NO_ERROR();
3317
3318 const char *vertESSL1 =
3319 "attribute vec4 a_pos;\n"
3320 "void main()\n"
3321 "{\n"
3322 " gl_Position = a_pos;\n"
3323 "}\n";
3324 const char *vertESSL3 =
3325 "#version 300 es\n"
3326 "in vec4 a_pos;\n"
3327 "void main()\n"
3328 "{\n"
3329 " gl_Position = a_pos;\n"
3330 "}\n";
3331
3332 GLenum allDrawBuffers[] = {
3333 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
3334 };
3335
3336 GLenum halfDrawBuffers[] = {
3337 GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
3338 };
3339
3340 // Test that when using gl_FragColor, only the first attachment is written to.
3341 const char *fragESSL1 =
3342 "precision highp float;\n"
3343 "void main()\n"
3344 "{\n"
3345 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
3346 "}\n";
3347 ANGLE_GL_PROGRAM(programESSL1, vertESSL1, fragESSL1);
3348
3349 {
3350 ClearEverythingToRed(renderbuffers);
3351
3352 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3353 DrawBuffers(useEXT, 4, allDrawBuffers);
3354 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
3355 ASSERT_GL_NO_ERROR();
3356
3357 CheckColors(renderbuffers, 0b0001, GLColor::green);
3358 CheckColors(renderbuffers, 0b1110, GLColor::red);
3359 }
3360
3361 // Test that when using gl_FragColor, but the first draw buffer is 0, then no attachment is
3362 // written to.
3363 {
3364 ClearEverythingToRed(renderbuffers);
3365
3366 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3367 DrawBuffers(useEXT, 4, halfDrawBuffers);
3368 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
3369 ASSERT_GL_NO_ERROR();
3370
3371 CheckColors(renderbuffers, 0b1111, GLColor::red);
3372 }
3373
3374 // Test what happens when rendering to a subset of the outputs. There is a behavior difference
3375 // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
3376 // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
3377 // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
3378 // attachments not declared in the shader should not be written to.
3379 const char *writeOddOutputsVert;
3380 const char *writeOddOutputsFrag;
3381 GLColor unwrittenColor;
3382 if (useEXT)
3383 {
3384 // In the extension, when an attachment isn't written to, it should get 0's
3385 unwrittenColor = GLColor(0, 0, 0, 0);
3386 writeOddOutputsVert = vertESSL1;
3387 writeOddOutputsFrag =
3388 "#extension GL_EXT_draw_buffers : require\n"
3389 "precision highp float;\n"
3390 "void main()\n"
3391 "{\n"
3392 " gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3393 " gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3394 "}\n";
3395 }
3396 else
3397 {
3398 // In ES3 if an attachment isn't declared, it shouldn't get written and should be red
3399 // because of the preceding clears.
3400 unwrittenColor = GLColor::red;
3401 writeOddOutputsVert = vertESSL3;
3402 writeOddOutputsFrag =
3403 "#version 300 es\n"
3404 "precision highp float;\n"
3405 "layout(location = 1) out vec4 output1;"
3406 "layout(location = 3) out vec4 output2;"
3407 "void main()\n"
3408 "{\n"
3409 " output1 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3410 " output2 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3411 "}\n";
3412 }
3413 ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
3414
3415 // Test that attachments not written to get the "unwritten" color
3416 {
3417 ClearEverythingToRed(renderbuffers);
3418
3419 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3420 DrawBuffers(useEXT, 4, allDrawBuffers);
3421 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3422 ASSERT_GL_NO_ERROR();
3423
3424 CheckColors(renderbuffers, 0b1010, GLColor::green);
3425 CheckColors(renderbuffers, 0b0101, unwrittenColor);
3426 }
3427
3428 // Test that attachments not written to get the "unwritten" color but that even when the
3429 // extension is used, disabled attachments are not written at all and stay red.
3430 {
3431 ClearEverythingToRed(renderbuffers);
3432
3433 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3434 DrawBuffers(useEXT, 4, halfDrawBuffers);
3435 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3436 ASSERT_GL_NO_ERROR();
3437
3438 CheckColors(renderbuffers, 0b1000, GLColor::green);
3439 CheckColors(renderbuffers, 0b0100, unwrittenColor);
3440 CheckColors(renderbuffers, 0b0011, GLColor::red);
3441 }
3442}
3443
Geoff Lang536eca12017-09-13 11:23:35 -04003444// Test that it's possible to generate mipmaps on unsized floating point textures once the
3445// extensions have been enabled
3446TEST_P(WebGLCompatibilityTest, GenerateMipmapUnsizedFloatingPointTexture)
3447{
3448 if (extensionRequestable("GL_OES_texture_float"))
3449 {
3450 glRequestExtensionANGLE("GL_OES_texture_float");
3451 }
3452 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_texture_float"));
3453
3454 GLTexture texture;
3455 glBindTexture(GL_TEXTURE_2D, texture);
3456
3457 constexpr GLColor32F data[4] = {
3458 kFloatRed, kFloatRed, kFloatGreen, kFloatBlue,
3459 };
3460 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_FLOAT, data);
3461 ASSERT_GL_NO_ERROR();
3462
3463 glGenerateMipmap(GL_TEXTURE_2D);
3464 EXPECT_GL_NO_ERROR();
3465}
3466// Test that it's possible to generate mipmaps on unsized floating point textures once the
3467// extensions have been enabled
3468TEST_P(WebGLCompatibilityTest, GenerateMipmapSizedFloatingPointTexture)
3469{
3470 if (extensionRequestable("GL_OES_texture_float"))
3471 {
3472 glRequestExtensionANGLE("GL_OES_texture_float");
3473 }
3474 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_texture_float"));
3475
3476 if (extensionRequestable("GL_EXT_texture_storage"))
3477 {
3478 glRequestExtensionANGLE("GL_EXT_texture_storage");
3479 }
3480 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_texture_storage"));
3481
3482 GLTexture texture;
3483 glBindTexture(GL_TEXTURE_2D, texture);
3484
3485 constexpr GLColor32F data[4] = {
3486 kFloatRed, kFloatRed, kFloatGreen, kFloatBlue,
3487 };
3488 glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA32F, 2, 2);
3489 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_FLOAT, data);
3490 ASSERT_GL_NO_ERROR();
3491
3492 glGenerateMipmap(GL_TEXTURE_2D);
3493 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3494
3495 if (extensionRequestable("GL_EXT_color_buffer_float"))
3496 {
3497 // Format is renderable but not filterable
3498 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
3499 glGenerateMipmap(GL_TEXTURE_2D);
3500 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3501 }
3502
3503 if (extensionRequestable("GL_EXT_color_buffer_float_linear"))
3504 {
3505 // Format is renderable but not filterable
3506 glRequestExtensionANGLE("GL_EXT_color_buffer_float_linear");
3507
3508 if (extensionEnabled("GL_EXT_color_buffer_float"))
3509 {
3510 // Format is filterable and renderable
3511 glGenerateMipmap(GL_TEXTURE_2D);
3512 EXPECT_GL_NO_ERROR();
3513 }
3514 else
3515 {
3516 // Format is filterable but not renderable
3517 glGenerateMipmap(GL_TEXTURE_2D);
3518 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3519 }
3520 }
3521}
3522
Frank Henigmanfccbac22017-05-28 17:29:26 -04003523// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
3524// qualifiers.
3525TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
3526{
3527 const std::string vertexShader =
3528 "#version 300 es\n"
3529 "uniform Block { mediump vec4 val; };\n"
3530 "void main() { gl_Position = val; }\n";
3531 const std::string fragmentShader =
3532 "#version 300 es\n"
3533 "uniform Block { highp vec4 val; };\n"
3534 "out highp vec4 out_FragColor;\n"
3535 "void main() { out_FragColor = val; }\n";
3536
3537 GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
3538 ASSERT_NE(0u, vs);
3539 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
3540 ASSERT_NE(0u, fs);
3541
3542 GLuint program = glCreateProgram();
3543
3544 glAttachShader(program, vs);
3545 glDeleteShader(vs);
3546 glAttachShader(program, fs);
3547 glDeleteShader(fs);
3548
3549 glLinkProgram(program);
3550 GLint linkStatus;
3551 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
3552 ASSERT_EQ(0, linkStatus);
3553
3554 glDeleteProgram(program);
3555}
3556
Geoff Lang69df2422017-07-05 12:42:31 -04003557// Test no attribute vertex shaders
3558TEST_P(WebGL2CompatibilityTest, NoAttributeVertexShader)
3559{
3560 const std::string vertexShader =
3561 "#version 300 es\n"
3562 "void main()\n"
3563 "{\n"
3564 "\n"
3565 " ivec2 xy = ivec2(gl_VertexID % 2, (gl_VertexID / 2 + gl_VertexID / 3) % 2);\n"
3566 " gl_Position = vec4(vec2(xy) * 2. - 1., 0, 1);\n"
3567 "}";
3568 const std::string fragmentShader =
3569 "#version 300 es\n"
3570 "precision mediump float;\n"
3571 "out vec4 result;\n"
3572 "void main()\n"
3573 "{\n"
3574 " result = vec4(0, 1, 0, 1);\n"
3575 "}";
3576
3577 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3578 glUseProgram(program);
3579
3580 glDrawArrays(GL_TRIANGLES, 0, 6);
3581 ASSERT_GL_NO_ERROR();
3582 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3583}
3584
Brandon Jonesed5b46f2017-07-21 08:39:17 -07003585// Tests bindAttribLocations for length limit
3586TEST_P(WebGL2CompatibilityTest, BindAttribLocationLimitation)
3587{
3588 constexpr int maxLocStringLength = 1024;
3589 const std::string tooLongString(maxLocStringLength + 1, '_');
3590
3591 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
3592
3593 EXPECT_GL_ERROR(GL_INVALID_VALUE);
3594}
3595
Geoff Langc287ea62016-09-16 14:46:51 -04003596// Use this to select which configurations (e.g. which renderer, which GLES major version) these
3597// tests should be run against.
3598ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
3599 ES2_D3D9(),
3600 ES2_D3D11(),
3601 ES3_D3D11(),
Geoff Langc287ea62016-09-16 14:46:51 -04003602 ES2_OPENGL(),
3603 ES3_OPENGL(),
3604 ES2_OPENGLES(),
3605 ES3_OPENGLES());
3606
Jamie Madill07be8bf2017-02-02 19:59:57 -05003607ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Geoff Langc287ea62016-09-16 14:46:51 -04003608} // namespace