blob: c64be19cf138b10371f5d7da7eb61dba26f65de4 [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
Bryan Bernhart (Intel Americas Inc)335d8bf2017-10-23 15:41:43 -07001514TEST_P(WebGLCompatibilityTest, ShaderSourceLineContinuation)
1515{
1516 // Verify that a line continuation character (i.e. backslash) cannot be used
1517 // within a preprocessor directive in a ES2 context.
1518 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1519
1520 const char *validVert =
1521 "#define foo this is a test\n"
1522 "precision mediump float;\n"
1523 "void main()\n"
1524 "{\n"
1525 " gl_Position = vec4(1.0);\n"
1526 "}\n";
1527
1528 const char *invalidVert =
1529 "#define foo this \\n"
1530 " is a test\n"
1531 "precision mediump float;\n"
1532 "void main()\n"
1533 "{\n"
1534 " gl_Position = vec4(1.0);\n"
1535 "}\n";
1536
1537 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1538 glShaderSource(shader, 1, &validVert, nullptr);
1539 EXPECT_GL_NO_ERROR();
1540
1541 glShaderSource(shader, 1, &invalidVert, nullptr);
1542 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1543 glDeleteShader(shader);
1544}
1545
1546// Test that line continuation is handled correctly when valdiating shader source
Geoff Langcab92ee2017-07-19 17:32:07 -04001547TEST_P(WebGL2CompatibilityTest, ShaderSourceLineContinuation)
1548{
1549 const char *validVert =
1550 "#version 300 es\n"
1551 "precision mediump float;\n"
1552 "\n"
1553 "void main ()\n"
1554 "{\n"
1555 " float f\\\n"
1556 "oo = 1.0;\n"
1557 " gl_Position = vec4(foo);\n"
1558 "}\n";
1559
1560 const char *invalidVert =
1561 "#version 300 es\n"
1562 "precision mediump float;\n"
1563 "\n"
1564 "void main ()\n"
1565 "{\n"
1566 " float f\\$\n"
1567 "oo = 1.0;\n"
1568 " gl_Position = vec4(foo);\n"
1569 "}\n";
1570
1571 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1572 glShaderSource(shader, 1, &validVert, nullptr);
1573 EXPECT_GL_NO_ERROR();
1574 glShaderSource(shader, 1, &invalidVert, nullptr);
1575 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1576 glDeleteShader(shader);
1577}
1578
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001579// Tests bindAttribLocations for reserved prefixes and length limits
1580TEST_P(WebGLCompatibilityTest, BindAttribLocationLimitation)
1581{
1582 constexpr int maxLocStringLength = 256;
1583 const std::string tooLongString(maxLocStringLength + 1, '_');
1584
1585 glBindAttribLocation(0, 0, "_webgl_var");
1586
1587 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1588
1589 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
1590
1591 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1592}
1593
Corentin Wallez0dc97812017-06-22 14:38:44 -04001594// Test that having no attributes with a zero divisor is valid in WebGL2
Geoff Lang407d4e72017-04-12 14:54:11 -04001595TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
1596{
1597 const std::string &vert =
1598 "attribute float a_pos;\n"
1599 "void main()\n"
1600 "{\n"
1601 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1602 "}\n";
1603
1604 const std::string &frag =
1605 "precision highp float;\n"
1606 "void main()\n"
1607 "{\n"
1608 " gl_FragColor = vec4(1.0);\n"
1609 "}\n";
1610
1611 ANGLE_GL_PROGRAM(program, vert, frag);
1612
1613 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1614 ASSERT_NE(-1, posLocation);
1615
1616 glUseProgram(program.get());
1617
1618 GLBuffer buffer;
1619 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1620 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1621
1622 glEnableVertexAttribArray(posLocation);
1623 glVertexAttribDivisor(posLocation, 1);
1624
Geoff Lang407d4e72017-04-12 14:54:11 -04001625 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1626 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
Geoff Lang407d4e72017-04-12 14:54:11 -04001627 ASSERT_GL_NO_ERROR();
1628}
1629
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001630// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
1631TEST_P(WebGLCompatibilityTest, NPOT)
1632{
1633 EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
1634
1635 // Create a texture and set an NPOT mip 0, should always be acceptable.
1636 GLTexture texture;
1637 glBindTexture(GL_TEXTURE_2D, texture.get());
1638 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1639 ASSERT_GL_NO_ERROR();
1640
1641 // Try setting an NPOT mip 1 and verify the error if WebGL 1
1642 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1643 if (getClientMajorVersion() < 3)
1644 {
1645 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1646 }
1647 else
1648 {
1649 ASSERT_GL_NO_ERROR();
1650 }
1651
1652 if (extensionRequestable("GL_OES_texture_npot"))
1653 {
1654 glRequestExtensionANGLE("GL_OES_texture_npot");
1655 ASSERT_GL_NO_ERROR();
1656
1657 // Try again to set NPOT mip 1
1658 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1659 ASSERT_GL_NO_ERROR();
1660 }
1661}
1662
Jamie Madillcad97ee2017-02-02 18:52:44 -05001663template <typename T>
1664void FillTexture2D(GLuint texture,
1665 GLsizei width,
1666 GLsizei height,
1667 const T &onePixelData,
1668 GLint level,
1669 GLint internalFormat,
1670 GLenum format,
1671 GLenum type)
1672{
1673 std::vector<T> allPixelsData(width * height, onePixelData);
1674
1675 glBindTexture(GL_TEXTURE_2D, texture);
1676 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
1677 allPixelsData.data());
1678 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1679 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1680 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1681 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1682}
1683
Frank Henigman875bbba2017-02-08 16:38:17 -05001684// Test that unset gl_Position defaults to (0,0,0,0).
1685TEST_P(WebGLCompatibilityTest, DefaultPosition)
1686{
1687 // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
1688 // and green otherwise. The center of each quadrant will be red if and only if all
1689 // four corners are red.
1690 const std::string vertexShader =
1691 "attribute vec3 pos;\n"
1692 "varying vec4 color;\n"
1693 "void main() {\n"
1694 " if (gl_Position == vec4(0,0,0,0)) {\n"
1695 " color = vec4(1,0,0,1);\n"
1696 " } else {\n"
1697 " color = vec4(0,1,0,1);\n"
1698 " }\n"
1699 " gl_Position = vec4(pos,1);\n"
1700 "}\n";
1701
1702 const std::string fragmentShader =
1703 "precision mediump float;\n"
1704 "varying vec4 color;\n"
1705 "void main() {\n"
1706 " gl_FragColor = color;\n"
1707 "}\n";
1708
1709 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1710 drawQuad(program.get(), "pos", 0.0f, 1.0f, true);
1711 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1712 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1713 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1714 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1715}
1716
Jamie Madilla4595b82017-01-11 17:36:34 -05001717// Tests that a rendering feedback loop triggers a GL error under WebGL.
1718// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
1719TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
1720{
1721 const std::string vertexShader =
1722 "attribute vec4 a_position;\n"
1723 "varying vec2 v_texCoord;\n"
1724 "void main() {\n"
1725 " gl_Position = a_position;\n"
1726 " v_texCoord = (a_position.xy * 0.5) + 0.5;\n"
1727 "}\n";
1728
1729 const std::string fragmentShader =
1730 "precision mediump float;\n"
1731 "varying vec2 v_texCoord;\n"
1732 "uniform sampler2D u_texture;\n"
1733 "void main() {\n"
1734 " // Shader swizzles color channels so we can tell if the draw succeeded.\n"
1735 " gl_FragColor = texture2D(u_texture, v_texCoord).gbra;\n"
1736 "}\n";
1737
1738 GLTexture texture;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001739 FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001740
1741 ASSERT_GL_NO_ERROR();
1742
1743 GLFramebuffer framebuffer;
1744 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1745 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1746
1747 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1748
1749 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1750
1751 GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
1752 ASSERT_NE(-1, uniformLoc);
1753
1754 glUseProgram(program.get());
1755 glUniform1i(uniformLoc, 0);
1756 glDisable(GL_BLEND);
1757 glDisable(GL_DEPTH_TEST);
1758 ASSERT_GL_NO_ERROR();
1759
1760 // Drawing with a texture that is also bound to the current framebuffer should fail
1761 glBindTexture(GL_TEXTURE_2D, texture.get());
1762 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1763 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1764
1765 // Ensure that the texture contents did not change after the previous render
1766 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1767 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1768 ASSERT_GL_NO_ERROR();
1769 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1770
1771 // Drawing when texture is bound to an inactive uniform should succeed
1772 GLTexture texture2;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001773 FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001774
1775 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1776 glActiveTexture(GL_TEXTURE1);
1777 glBindTexture(GL_TEXTURE_2D, texture.get());
1778 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1779 ASSERT_GL_NO_ERROR();
1780 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1781}
1782
Bryan Bernhart58806562017-01-05 13:09:31 -08001783// Test for the max draw buffers and color attachments.
1784TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
1785{
1786 // This test only applies to ES2.
1787 if (getClientMajorVersion() != 2)
1788 {
1789 return;
1790 }
1791
1792 GLFramebuffer fbo[2];
1793 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
1794
1795 // Test that is valid when we bind with a single attachment point.
1796 GLTexture texture;
1797 glBindTexture(GL_TEXTURE_2D, texture.get());
1798 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1799 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1800 ASSERT_GL_NO_ERROR();
1801
1802 // Test that enabling the draw buffers extension will allow us to bind with a non-zero
1803 // attachment point.
1804 if (extensionRequestable("GL_EXT_draw_buffers"))
1805 {
1806 glRequestExtensionANGLE("GL_EXT_draw_buffers");
1807 EXPECT_GL_NO_ERROR();
1808 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
1809
1810 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
1811
1812 GLTexture texture2;
1813 glBindTexture(GL_TEXTURE_2D, texture2.get());
1814 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1815 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
1816 0);
1817 ASSERT_GL_NO_ERROR();
1818 }
1819}
1820
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001821// Test that the offset in the index buffer is forced to be a multiple of the element size
1822TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
1823{
1824 const std::string &vert =
1825 "attribute vec3 a_pos;\n"
1826 "void main()\n"
1827 "{\n"
1828 " gl_Position = vec4(a_pos, 1.0);\n"
1829 "}\n";
1830
1831 const std::string &frag =
1832 "precision highp float;\n"
1833 "void main()\n"
1834 "{\n"
1835 " gl_FragColor = vec4(1.0);\n"
1836 "}\n";
1837
1838 ANGLE_GL_PROGRAM(program, vert, frag);
1839
1840 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1841 ASSERT_NE(-1, posLocation);
1842 glUseProgram(program.get());
1843
1844 const auto &vertices = GetQuadVertices();
1845
1846 GLBuffer vertexBuffer;
1847 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1848 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1849 GL_STATIC_DRAW);
1850
1851 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1852 glEnableVertexAttribArray(posLocation);
1853
1854 GLBuffer indexBuffer;
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001855 const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0, 0};
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001856 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1857 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
1858
1859 ASSERT_GL_NO_ERROR();
1860
1861 const char *zeroIndices = nullptr;
1862
1863 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
1864 ASSERT_GL_NO_ERROR();
1865
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001866 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001867 ASSERT_GL_NO_ERROR();
1868
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001869 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices + 1);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001870 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1871}
1872
1873// Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
1874// size
1875TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
1876{
1877 const char *zeroOffset = nullptr;
1878
1879 // Base case, vector of two floats
1880 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
1881 ASSERT_GL_NO_ERROR();
1882
1883 // Test setting a non-multiple offset
1884 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
1885 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1886 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
1887 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1888 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
1889 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1890
1891 // Test setting a non-multiple stride
1892 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
1893 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1894 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
1895 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1896 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
1897 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1898}
1899
Jamie Madillcad97ee2017-02-02 18:52:44 -05001900void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
1901 const std::array<GLenum, 2> &drawBuffers,
1902 GLenum expectedError)
1903{
1904 glDrawBuffersEXT(2, drawBuffers.data());
1905
1906 // Make sure framebuffer is complete before feedback loop detection
1907 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1908
1909 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
1910
1911 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
1912 // it should be NO_ERROR"
1913 EXPECT_GL_ERROR(expectedError);
1914}
1915
1916// This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
1917// Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
1918TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
1919{
1920 const std::string vertexShader =
1921 "attribute vec4 aPosition;\n"
1922 "varying vec2 texCoord;\n"
1923 "void main() {\n"
1924 " gl_Position = aPosition;\n"
1925 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
1926 "}\n";
1927
1928 const std::string fragmentShader =
1929 "#extension GL_EXT_draw_buffers : require\n"
1930 "precision mediump float;\n"
1931 "uniform sampler2D tex;\n"
1932 "varying vec2 texCoord;\n"
1933 "void main() {\n"
1934 " gl_FragData[0] = texture2D(tex, texCoord);\n"
1935 " gl_FragData[1] = texture2D(tex, texCoord);\n"
1936 "}\n";
1937
1938 GLsizei width = 8;
1939 GLsizei height = 8;
1940
1941 // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
1942 // extension and gl_FragData semantics are changed to enforce indexing by zero always.
1943 // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
1944 if (/*!extensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
1945 {
1946 // No WEBGL_draw_buffers support -- this is legal.
1947 return;
1948 }
1949
1950 GLint maxDrawBuffers = 0;
1951 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1952
1953 if (maxDrawBuffers < 2)
1954 {
1955 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
1956 return;
1957 }
1958
1959 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1960 glUseProgram(program.get());
1961 glViewport(0, 0, width, height);
1962
1963 GLTexture tex0;
1964 GLTexture tex1;
1965 GLFramebuffer fbo;
1966 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1967 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1968 ASSERT_GL_NO_ERROR();
1969
1970 glBindTexture(GL_TEXTURE_2D, tex1.get());
1971 GLint texLoc = glGetUniformLocation(program.get(), "tex");
1972 ASSERT_NE(-1, texLoc);
1973 glUniform1i(texLoc, 0);
1974 ASSERT_GL_NO_ERROR();
1975
1976 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
1977 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
1978 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
1979 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
1980
1981 drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
1982 GL_INVALID_OPERATION);
1983 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
1984 GL_INVALID_OPERATION);
1985 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
1986}
1987
Jamie Madill07be8bf2017-02-02 19:59:57 -05001988// Test tests that texture copying feedback loops are properly rejected in WebGL.
1989// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
1990TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
1991{
1992 GLTexture texture;
1993 glBindTexture(GL_TEXTURE_2D, texture.get());
1994 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1995 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1996 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1997 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1998 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1999
2000 GLTexture texture2;
2001 glBindTexture(GL_TEXTURE_2D, texture2.get());
2002 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2003 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2004 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2005 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2006 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2007
2008 GLFramebuffer framebuffer;
2009 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2010 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2011
2012 // framebuffer should be FRAMEBUFFER_COMPLETE.
2013 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2014 ASSERT_GL_NO_ERROR();
2015
2016 // testing copyTexImage2D
2017
2018 // copyTexImage2D to same texture but different level
2019 glBindTexture(GL_TEXTURE_2D, texture.get());
2020 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
2021 EXPECT_GL_NO_ERROR();
2022
2023 // copyTexImage2D to same texture same level, invalid feedback loop
2024 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2025 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2026
2027 // copyTexImage2D to different texture
2028 glBindTexture(GL_TEXTURE_2D, texture2.get());
2029 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
2030 EXPECT_GL_NO_ERROR();
2031
2032 // testing copyTexSubImage2D
2033
2034 // copyTexSubImage2D to same texture but different level
2035 glBindTexture(GL_TEXTURE_2D, texture.get());
2036 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
2037 EXPECT_GL_NO_ERROR();
2038
2039 // copyTexSubImage2D to same texture same level, invalid feedback loop
2040 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2041 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2042
2043 // copyTexSubImage2D to different texture
2044 glBindTexture(GL_TEXTURE_2D, texture2.get());
2045 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
2046 EXPECT_GL_NO_ERROR();
2047}
2048
2049void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
2050 const std::array<GLenum, 2> &drawBuffers,
2051 GLenum expectedError)
2052{
2053 glDrawBuffers(2, drawBuffers.data());
2054
2055 // Make sure framebuffer is complete before feedback loop detection
2056 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2057
2058 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
2059
2060 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
2061 // it should be NO_ERROR"
2062 EXPECT_GL_ERROR(expectedError);
2063}
2064
Yuly Novikov817232e2017-02-22 18:36:10 -05002065// Tests invariance matching rules between built in varyings.
2066// Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
2067TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
2068{
2069 const std::string vertexShaderVariant =
2070 "varying vec4 v_varying;\n"
2071 "void main()\n"
2072 "{\n"
2073 " gl_PointSize = 1.0;\n"
2074 " gl_Position = v_varying;\n"
2075 "}";
2076 const std::string fragmentShaderInvariantGlFragCoord =
2077 "invariant gl_FragCoord;\n"
2078 "void main()\n"
2079 "{\n"
2080 " gl_FragColor = gl_FragCoord;\n"
2081 "}";
2082 const std::string fragmentShaderInvariantGlPointCoord =
2083 "invariant gl_PointCoord;\n"
2084 "void main()\n"
2085 "{\n"
2086 " gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);\n"
2087 "}";
2088
2089 GLuint program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlFragCoord);
2090 EXPECT_EQ(0u, program);
2091
2092 program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlPointCoord);
2093 EXPECT_EQ(0u, program);
2094}
2095
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04002096// Tests global namespace conflicts between uniforms and attributes.
2097// Based on WebGL test conformance/glsl/misc/shaders-with-name-conflicts.html.
2098TEST_P(WebGLCompatibilityTest, GlobalNamesConflict)
2099{
2100 const std::string vertexShader =
2101 "attribute vec4 foo;\n"
2102 "void main()\n"
2103 "{\n"
2104 " gl_Position = foo;\n"
2105 "}";
2106 const std::string fragmentShader =
2107 "precision mediump float;\n"
2108 "uniform vec4 foo;\n"
2109 "void main()\n"
2110 "{\n"
2111 " gl_FragColor = foo;\n"
2112 "}";
2113
2114 GLuint program = CompileProgram(vertexShader, fragmentShader);
2115 EXPECT_EQ(0u, program);
2116}
2117
Geoff Lang966c9402017-04-18 12:38:27 -04002118// Test dimension and image size validation of compressed textures
2119TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
2120{
2121 if (extensionRequestable("GL_EXT_texture_compression_dxt1"))
2122 {
2123 glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
2124 }
2125
2126 if (!extensionEnabled("GL_EXT_texture_compression_dxt1"))
2127 {
2128 std::cout << "Test skipped because GL_EXT_texture_compression_dxt1 is not available."
2129 << std::endl;
2130 return;
2131 }
2132
2133 constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
2134
2135 GLTexture texture;
2136 glBindTexture(GL_TEXTURE_2D, texture);
2137
2138 // Regular case, verify that it works
2139 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2140 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2141 ASSERT_GL_NO_ERROR();
2142
2143 // Test various dimensions that are not valid
2144 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
2145 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2146 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2147
2148 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
2149 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2150 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2151
2152 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2153 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2154 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2155
2156 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2157 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2158 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2159
2160 // Test various image sizes that are not valid
2161 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2162 sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
2163 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2164
2165 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2166 sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
2167 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2168
2169 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
2170 CompressedImageDXT1);
2171 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2172
2173 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
2174 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2175 ASSERT_GL_ERROR(GL_INVALID_VALUE);
2176
2177 // Fill a full mip chain and verify that it works
2178 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
2179 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2180 glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
2181 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2182 glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
2183 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2184 ASSERT_GL_NO_ERROR();
2185
2186 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2187 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2188 ASSERT_GL_NO_ERROR();
2189
2190 // Test that non-block size sub-uploads are not valid for the 0 mip
2191 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2192 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2193 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2194
2195 // Test that non-block size sub-uploads are valid for if they fill the whole mip
2196 glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2197 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2198 glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
2199 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2200 ASSERT_GL_NO_ERROR();
2201
2202 // Test that if the format miss-matches the texture, an error is generated
2203 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
2204 sizeof(CompressedImageDXT1), CompressedImageDXT1);
2205 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2206}
2207
Geoff Lang677bb6f2017-04-05 12:40:40 -04002208TEST_P(WebGLCompatibilityTest, L32FTextures)
2209{
2210 constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f};
2211 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
2212
2213 for (auto extension : FloatingPointTextureExtensions)
2214 {
2215 if (strlen(extension) > 0 && extensionRequestable(extension))
2216 {
2217 glRequestExtensionANGLE(extension);
2218 ASSERT_GL_NO_ERROR();
2219 }
2220
2221 // Unsized L 32F
2222 {
2223 bool texture = extensionEnabled("GL_OES_texture_float");
2224 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2225 bool render = false;
2226 TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
2227 textureData, readPixelData);
2228 }
2229
2230 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2231 {
2232 // Sized L 32F
2233 bool texture = extensionEnabled("GL_OES_texture_float") &&
2234 extensionEnabled("GL_EXT_texture_storage");
2235 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2236 bool render = false;
2237 TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
2238 render, textureData, readPixelData);
2239 }
2240 }
2241}
2242
2243TEST_P(WebGLCompatibilityTest, A32FTextures)
2244{
2245 constexpr float textureData[] = {33.33f, 0.0f, 0.0f, 0.0f};
2246 constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
2247
2248 for (auto extension : FloatingPointTextureExtensions)
2249 {
2250 if (strlen(extension) > 0 && extensionRequestable(extension))
2251 {
2252 glRequestExtensionANGLE(extension);
2253 ASSERT_GL_NO_ERROR();
2254 }
2255
2256 // Unsized A 32F
2257 {
2258 bool texture = extensionEnabled("GL_OES_texture_float");
2259 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2260 bool render = false;
2261 TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
2262 textureData, readPixelData);
2263 }
2264
2265 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2266 {
2267 // Sized A 32F
2268 bool texture = extensionEnabled("GL_OES_texture_float") &&
2269 extensionEnabled("GL_EXT_texture_storage");
2270 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2271 bool render = false;
2272 TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
2273 textureData, readPixelData);
2274 }
2275 }
2276}
2277
2278TEST_P(WebGLCompatibilityTest, LA32FTextures)
2279{
2280 constexpr float textureData[] = {-0.21f, 15.1f, 0.0f, 0.0f};
2281 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
2282 textureData[1]};
2283
2284 for (auto extension : FloatingPointTextureExtensions)
2285 {
2286 if (strlen(extension) > 0 && extensionRequestable(extension))
2287 {
2288 glRequestExtensionANGLE(extension);
2289 ASSERT_GL_NO_ERROR();
2290 }
2291
2292 // Unsized LA 32F
2293 {
2294 bool texture = extensionEnabled("GL_OES_texture_float");
2295 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2296 bool render = false;
2297 TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
2298 filter, render, textureData, readPixelData);
2299 }
2300
2301 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2302 {
2303 // Sized LA 32F
2304 bool texture = extensionEnabled("GL_OES_texture_float") &&
2305 extensionEnabled("GL_EXT_texture_storage");
2306 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2307 bool render = false;
2308 TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
2309 filter, render, textureData, readPixelData);
2310 }
2311 }
2312}
2313
2314TEST_P(WebGLCompatibilityTest, R32FTextures)
2315{
2316 constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
2317
2318 for (auto extension : FloatingPointTextureExtensions)
2319 {
2320 if (strlen(extension) > 0 && extensionRequestable(extension))
2321 {
2322 glRequestExtensionANGLE(extension);
2323 ASSERT_GL_NO_ERROR();
2324 }
2325
2326 // Unsized R 32F
2327 {
2328 bool texture =
2329 extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg");
2330 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2331 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2332 TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
2333 }
2334
2335 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2336 {
2337 // Sized R 32F
2338 bool texture =
2339 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2340 extensionEnabled("GL_EXT_texture_rg") &&
2341 extensionEnabled("GL_EXT_texture_storage"));
2342 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2343 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2344 TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
2345 }
2346 }
2347}
2348
2349TEST_P(WebGLCompatibilityTest, RG32FTextures)
2350{
2351 constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
2352
2353 for (auto extension : FloatingPointTextureExtensions)
2354 {
2355 if (strlen(extension) > 0 && extensionRequestable(extension))
2356 {
2357 glRequestExtensionANGLE(extension);
2358 ASSERT_GL_NO_ERROR();
2359 }
2360
2361 // Unsized RG 32F
2362 {
2363 bool texture =
2364 (extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg"));
2365 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2366 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2367 TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
2368 }
2369
2370 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2371 {
2372 // Sized RG 32F
2373 bool texture =
2374 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2375 extensionEnabled("GL_EXT_texture_rg") &&
2376 extensionEnabled("GL_EXT_texture_storage"));
2377 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2378 bool render = extensionEnabled("GL_EXT_color_buffer_float");
2379 TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
2380 }
2381 }
2382}
2383
2384TEST_P(WebGLCompatibilityTest, RGB32FTextures)
2385{
Geoff Lang40762ef2017-05-08 13:47:03 -04002386 if (IsLinux() && IsIntel())
2387 {
2388 std::cout << "Test skipped on Linux Intel." << std::endl;
2389 return;
2390 }
2391
Geoff Lang677bb6f2017-04-05 12:40:40 -04002392 constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
2393
2394 for (auto extension : FloatingPointTextureExtensions)
2395 {
2396 if (strlen(extension) > 0 && extensionRequestable(extension))
2397 {
2398 glRequestExtensionANGLE(extension);
2399 ASSERT_GL_NO_ERROR();
2400 }
2401
2402 // Unsized RGB 32F
2403 {
2404 bool texture = extensionEnabled("GL_OES_texture_float");
2405 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2406 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
2407 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
2408 }
2409
2410 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2411 {
2412 // Sized RGBA 32F
2413 bool texture =
2414 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2415 extensionEnabled("GL_EXT_texture_storage"));
2416 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2417 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
2418 TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
2419 data);
2420 }
2421 }
2422}
2423
2424TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
2425{
2426 constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2427
2428 for (auto extension : FloatingPointTextureExtensions)
2429 {
2430 if (strlen(extension) > 0 && extensionRequestable(extension))
2431 {
2432 glRequestExtensionANGLE(extension);
2433 ASSERT_GL_NO_ERROR();
2434 }
2435
2436 // Unsized RGBA 32F
2437 {
2438 bool texture = extensionEnabled("GL_OES_texture_float");
2439 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2440 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2441 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2442 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
2443 }
2444
2445 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2446 {
2447 // Sized RGBA 32F
2448 bool texture =
2449 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2450 extensionEnabled("GL_EXT_texture_storage"));
2451 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2452 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2453 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2454 TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
2455 data);
2456 }
2457 }
2458}
2459
2460TEST_P(WebGLCompatibilityTest, R16FTextures)
2461{
2462 constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
2463 const GLushort textureData[] = {
2464 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2465 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2466
2467 for (auto extension : FloatingPointTextureExtensions)
2468 {
2469 if (strlen(extension) > 0 && extensionRequestable(extension))
2470 {
2471 glRequestExtensionANGLE(extension);
2472 ASSERT_GL_NO_ERROR();
2473 }
2474
2475 // Unsized R 16F (OES)
2476 {
2477 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2478 extensionEnabled("GL_EXT_texture_rg");
2479 bool filter = getClientMajorVersion() >= 3 ||
2480 extensionEnabled("GL_OES_texture_half_float_linear");
2481 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2482 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
2483 textureData, readPixelsData);
2484 }
2485
2486 // Unsized R 16F
2487 {
2488 bool texture = false;
2489 bool filter = false;
2490 bool render = false;
2491 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2492 textureData, readPixelsData);
2493 }
2494
2495 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2496 {
2497 // Sized R 16F
2498 bool texture = getClientMajorVersion() >= 3;
2499 bool filter = getClientMajorVersion() >= 3 ||
2500 extensionEnabled("GL_OES_texture_half_float_linear");
2501 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2502 extensionEnabled("GL_EXT_color_buffer_float");
2503 TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2504 textureData, readPixelsData);
2505 }
2506 }
2507}
2508
2509TEST_P(WebGLCompatibilityTest, RG16FTextures)
2510{
2511 constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
2512 const GLushort textureData[] = {
2513 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2514 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2515
2516 for (auto extension : FloatingPointTextureExtensions)
2517 {
2518 if (strlen(extension) > 0 && extensionRequestable(extension))
2519 {
2520 glRequestExtensionANGLE(extension);
2521 ASSERT_GL_NO_ERROR();
2522 }
2523
2524 // Unsized RG 16F (OES)
2525 {
2526 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2527 extensionEnabled("GL_EXT_texture_rg");
2528 bool filter = getClientMajorVersion() >= 3 ||
2529 extensionEnabled("GL_OES_texture_half_float_linear");
2530 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") &&
2531 extensionEnabled("GL_EXT_texture_rg");
2532 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
2533 textureData, readPixelsData);
2534 }
2535
2536 // Unsized RG 16F
2537 {
2538 bool texture = false;
2539 bool filter = false;
2540 bool render = false;
2541 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2542 textureData, readPixelsData);
2543 }
2544
2545 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2546 {
2547 // Sized RG 16F
2548 bool texture = getClientMajorVersion() >= 3;
2549 bool filter = getClientMajorVersion() >= 3 ||
2550 extensionEnabled("GL_OES_texture_half_float_linear");
2551 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2552 extensionEnabled("GL_EXT_color_buffer_float");
2553 TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2554 textureData, readPixelsData);
2555 }
2556 }
2557}
2558
2559TEST_P(WebGLCompatibilityTest, RGB16FTextures)
2560{
Geoff Lang40762ef2017-05-08 13:47:03 -04002561 if (IsOzone() && IsIntel())
2562 {
2563 std::cout << "Test skipped on Intel Ozone." << std::endl;
2564 return;
2565 }
2566
Geoff Lang677bb6f2017-04-05 12:40:40 -04002567 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
2568 const GLushort textureData[] = {
2569 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2570 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2571
2572 for (auto extension : FloatingPointTextureExtensions)
2573 {
2574 if (strlen(extension) > 0 && extensionRequestable(extension))
2575 {
2576 glRequestExtensionANGLE(extension);
2577 ASSERT_GL_NO_ERROR();
2578 }
2579
2580 // Unsized RGB 16F (OES)
2581 {
2582 bool texture = extensionEnabled("GL_OES_texture_half_float");
2583 bool filter = getClientMajorVersion() >= 3 ||
2584 extensionEnabled("GL_OES_texture_half_float_linear");
2585 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2586 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
2587 textureData, readPixelsData);
2588 }
2589
2590 // Unsized RGB 16F
2591 {
2592 bool texture = false;
2593 bool filter = false;
2594 bool render = false;
2595 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2596 textureData, readPixelsData);
2597 }
2598
2599 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2600 {
2601 // Sized RGB 16F
2602 bool texture = getClientMajorVersion() >= 3;
2603 bool filter = getClientMajorVersion() >= 3 ||
2604 extensionEnabled("GL_OES_texture_half_float_linear");
2605 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2606 TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2607 textureData, readPixelsData);
2608 }
2609 }
2610}
2611
2612TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
2613{
Geoff Lang40762ef2017-05-08 13:47:03 -04002614 if (IsOzone() && IsIntel())
2615 {
2616 std::cout << "Test skipped on Intel Ozone." << std::endl;
2617 return;
2618 }
2619
Geoff Lang677bb6f2017-04-05 12:40:40 -04002620 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2621 const GLushort textureData[] = {
2622 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2623 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2624
2625 for (auto extension : FloatingPointTextureExtensions)
2626 {
2627 if (strlen(extension) > 0 && extensionRequestable(extension))
2628 {
2629 glRequestExtensionANGLE(extension);
2630 ASSERT_GL_NO_ERROR();
2631 }
2632
2633 // Unsized RGBA 16F (OES)
2634 {
2635 bool texture = extensionEnabled("GL_OES_texture_half_float");
2636 bool filter = getClientMajorVersion() >= 3 ||
2637 extensionEnabled("GL_OES_texture_half_float_linear");
2638 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2639 extensionEnabled("GL_EXT_color_buffer_float");
2640 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
2641 textureData, readPixelsData);
2642 }
2643
2644 // Unsized RGBA 16F
2645 {
2646 bool texture = false;
2647 bool filter = false;
2648 bool render = false;
2649 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2650 textureData, readPixelsData);
2651 }
2652
2653 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2654 {
2655 // Sized RGBA 16F
2656 bool texture = getClientMajorVersion() >= 3;
2657 bool filter = getClientMajorVersion() >= 3 ||
2658 extensionEnabled("GL_OES_texture_half_float_linear");
2659 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2660 extensionEnabled("GL_EXT_color_buffer_float");
2661 TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2662 textureData, readPixelsData);
2663 }
2664 }
2665}
2666
Geoff Lang6e898aa2017-06-02 11:17:26 -04002667// Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
2668// accepted by glTexImage2D
2669TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
2670{
2671 if (getClientMajorVersion() != 2)
2672 {
2673 std::cout << "Test skipped because it is only valid for WebGL1 contexts." << std::endl;
2674 return;
2675 }
2676
2677 if (!extensionRequestable("GL_OES_texture_float"))
2678 {
2679 std::cout << "Test skipped because GL_OES_texture_float is not requestable." << std::endl;
2680 return;
2681 }
2682 glRequestExtensionANGLE("GL_OES_texture_float");
2683 ASSERT_GL_NO_ERROR();
2684
2685 GLTexture texture;
2686 glBindTexture(GL_TEXTURE_2D, texture);
2687
2688 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2689 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2690
2691 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2692 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2693
2694 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
2695 {
2696 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
2697 ASSERT_GL_NO_ERROR();
2698
2699 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2700 EXPECT_GL_NO_ERROR();
2701 }
2702
2703 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
2704 {
2705 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
2706 ASSERT_GL_NO_ERROR();
2707
2708 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2709 EXPECT_GL_NO_ERROR();
2710 }
2711}
2712
Jamie Madill07be8bf2017-02-02 19:59:57 -05002713// This tests that rendering feedback loops works as expected with WebGL 2.
2714// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
2715TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
2716{
2717 const std::string vertexShader =
2718 "#version 300 es\n"
2719 "in vec4 aPosition;\n"
2720 "out vec2 texCoord;\n"
2721 "void main() {\n"
2722 " gl_Position = aPosition;\n"
2723 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2724 "}\n";
2725
2726 const std::string fragmentShader =
2727 "#version 300 es\n"
2728 "precision mediump float;\n"
2729 "uniform sampler2D tex;\n"
2730 "in vec2 texCoord;\n"
2731 "out vec4 oColor;\n"
2732 "void main() {\n"
2733 " oColor = texture(tex, texCoord);\n"
2734 "}\n";
2735
2736 GLsizei width = 8;
2737 GLsizei height = 8;
2738
2739 GLint maxDrawBuffers = 0;
2740 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2741 // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
2742 ASSERT_GE(maxDrawBuffers, 2);
2743
2744 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2745 glUseProgram(program.get());
2746 glViewport(0, 0, width, height);
2747
2748 GLTexture tex0;
2749 GLTexture tex1;
2750 GLFramebuffer fbo;
2751 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2752 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2753 ASSERT_GL_NO_ERROR();
2754
2755 glBindTexture(GL_TEXTURE_2D, tex1.get());
2756 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2757 ASSERT_NE(-1, texLoc);
2758 glUniform1i(texLoc, 0);
2759
2760 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2761 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2762 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2763 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
2764 ASSERT_GL_NO_ERROR();
2765
2766 drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
2767 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2768 GL_INVALID_OPERATION);
2769 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
2770}
2771
Jamie Madill1d37bc52017-02-02 19:59:58 -05002772// This test covers detection of rendering feedback loops between the FBO and a depth Texture.
2773// Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
2774TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
2775{
2776 const std::string vertexShader =
2777 "#version 300 es\n"
2778 "in vec4 aPosition;\n"
2779 "out vec2 texCoord;\n"
2780 "void main() {\n"
2781 " gl_Position = aPosition;\n"
2782 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2783 "}\n";
2784
2785 const std::string fragmentShader =
2786 "#version 300 es\n"
2787 "precision mediump float;\n"
2788 "uniform sampler2D tex;\n"
2789 "in vec2 texCoord;\n"
2790 "out vec4 oColor;\n"
2791 "void main() {\n"
2792 " oColor = texture(tex, texCoord);\n"
2793 "}\n";
2794
2795 GLsizei width = 8;
2796 GLsizei height = 8;
2797
2798 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2799 glUseProgram(program.get());
2800
2801 glViewport(0, 0, width, height);
2802
2803 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2804 glUniform1i(texLoc, 0);
2805
2806 // Create textures and allocate storage
2807 GLTexture tex0;
2808 GLTexture tex1;
2809 GLRenderbuffer rb;
2810 FillTexture2D(tex0.get(), width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2811 FillTexture2D(tex1.get(), width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
2812 GL_UNSIGNED_INT);
2813 glBindRenderbuffer(GL_RENDERBUFFER, rb.get());
2814 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
2815 ASSERT_GL_NO_ERROR();
2816
2817 GLFramebuffer fbo;
2818 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2819 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2820
2821 // Test rendering and sampling feedback loop for depth buffer
2822 glBindTexture(GL_TEXTURE_2D, tex1.get());
2823 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1.get(), 0);
2824 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2825
2826 // The same image is used as depth buffer during rendering.
2827 glEnable(GL_DEPTH_TEST);
2828 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2829 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2830
2831 // The same image is used as depth buffer. But depth mask is false.
2832 glDepthMask(GL_FALSE);
2833 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2834 EXPECT_GL_NO_ERROR();
2835
2836 // The same image is used as depth buffer. But depth test is not enabled during rendering.
2837 glDepthMask(GL_TRUE);
2838 glDisable(GL_DEPTH_TEST);
2839 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2840 EXPECT_GL_NO_ERROR();
2841
2842 // Test rendering and sampling feedback loop for stencil buffer
2843 glBindTexture(GL_RENDERBUFFER, rb.get());
2844 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
2845 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb.get());
2846 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2847 constexpr GLint stencilClearValue = 0x40;
2848 glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
2849
2850 // The same image is used as stencil buffer during rendering.
2851 glEnable(GL_STENCIL_TEST);
2852 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2853 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2854
2855 // The same image is used as stencil buffer. But stencil mask is zero.
2856 glStencilMask(0x0);
2857 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2858 EXPECT_GL_NO_ERROR();
2859
2860 // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
2861 glStencilMask(0xffff);
2862 glDisable(GL_STENCIL_TEST);
2863 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2864 EXPECT_GL_NO_ERROR();
2865}
2866
Jamie Madillfd3dd432017-02-02 19:59:59 -05002867// The source and the target for CopyTexSubImage3D are the same 3D texture.
2868// But the level of the 3D texture != the level of the read attachment.
2869TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
2870{
2871 GLTexture texture;
2872 GLFramebuffer framebuffer;
2873
2874 glBindTexture(GL_TEXTURE_3D, texture.get());
2875 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2876
2877 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2878 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2879 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
2880 ASSERT_GL_NO_ERROR();
2881
2882 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2883 EXPECT_GL_NO_ERROR();
2884}
2885
2886// The source and the target for CopyTexSubImage3D are the same 3D texture.
2887// But the zoffset of the 3D texture != the layer of the read attachment.
2888TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
2889{
2890 GLTexture texture;
2891 GLFramebuffer framebuffer;
2892
2893 glBindTexture(GL_TEXTURE_3D, texture.get());
2894 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2895
2896 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2897 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 1);
2898 ASSERT_GL_NO_ERROR();
2899
2900 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
2901 EXPECT_GL_NO_ERROR();
2902}
2903
2904// The source and the target for CopyTexSubImage3D are the same 3D texture.
2905// And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
2906TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
2907{
2908 GLTexture texture;
2909 GLFramebuffer framebuffer;
2910
2911 glBindTexture(GL_TEXTURE_3D, texture.get());
2912 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2913
2914 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2915 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2916 glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2917 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 1, 0);
2918 ASSERT_GL_NO_ERROR();
2919
2920 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2921 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2922}
2923
Corentin Wallez59c41592017-07-11 13:19:54 -04002924// Verify that errors are generated when there isn't a defined conversion between the clear type and
2925// the buffer type.
Geoff Lang76e65652017-03-27 14:58:02 -04002926TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
2927{
2928 if (IsD3D11())
2929 {
2930 std::cout << "Test skipped because it generates D3D11 runtime warnings." << std::endl;
2931 return;
2932 }
2933
2934 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
2935 constexpr int clearInt[] = {0, 0, 0, 0};
2936 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
2937
2938 GLTexture texture;
2939 GLFramebuffer framebuffer;
2940
2941 glBindTexture(GL_TEXTURE_2D, texture.get());
2942 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2943
2944 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2945 ASSERT_GL_NO_ERROR();
2946
2947 // Unsigned integer buffer
2948 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
2949 ASSERT_GL_NO_ERROR();
2950
2951 glClearBufferfv(GL_COLOR, 0, clearFloat);
2952 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2953
2954 glClearBufferiv(GL_COLOR, 0, clearInt);
2955 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2956
2957 glClearBufferuiv(GL_COLOR, 0, clearUint);
2958 EXPECT_GL_NO_ERROR();
2959
2960 glClear(GL_COLOR_BUFFER_BIT);
2961 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2962
2963 // Integer buffer
2964 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
2965 ASSERT_GL_NO_ERROR();
2966
2967 glClearBufferfv(GL_COLOR, 0, clearFloat);
2968 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2969
2970 glClearBufferiv(GL_COLOR, 0, clearInt);
2971 EXPECT_GL_NO_ERROR();
2972
2973 glClearBufferuiv(GL_COLOR, 0, clearUint);
2974 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2975
2976 glClear(GL_COLOR_BUFFER_BIT);
2977 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2978
2979 // Float buffer
Geoff Lang677bb6f2017-04-05 12:40:40 -04002980 if (extensionRequestable("GL_EXT_color_buffer_float"))
2981 {
2982 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
2983 }
Geoff Lang76e65652017-03-27 14:58:02 -04002984
Geoff Lang677bb6f2017-04-05 12:40:40 -04002985 if (extensionEnabled("GL_EXT_color_buffer_float"))
2986 {
2987 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2988 ASSERT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002989
Geoff Lang677bb6f2017-04-05 12:40:40 -04002990 glClearBufferfv(GL_COLOR, 0, clearFloat);
2991 EXPECT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002992
Geoff Lang677bb6f2017-04-05 12:40:40 -04002993 glClearBufferiv(GL_COLOR, 0, clearInt);
2994 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang76e65652017-03-27 14:58:02 -04002995
Geoff Lang677bb6f2017-04-05 12:40:40 -04002996 glClearBufferuiv(GL_COLOR, 0, clearUint);
2997 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2998
2999 glClear(GL_COLOR_BUFFER_BIT);
3000 EXPECT_GL_NO_ERROR();
3001 }
Geoff Lang76e65652017-03-27 14:58:02 -04003002
3003 // Normalized uint buffer
3004 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
3005 ASSERT_GL_NO_ERROR();
3006
3007 glClearBufferfv(GL_COLOR, 0, clearFloat);
3008 EXPECT_GL_NO_ERROR();
3009
3010 glClearBufferiv(GL_COLOR, 0, clearInt);
3011 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3012
3013 glClearBufferuiv(GL_COLOR, 0, clearUint);
3014 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3015
3016 glClear(GL_COLOR_BUFFER_BIT);
3017 EXPECT_GL_NO_ERROR();
3018}
3019
Corentin Wallez59c41592017-07-11 13:19:54 -04003020// Test the interaction of WebGL compatibility clears with default framebuffers
3021TEST_P(WebGL2CompatibilityTest, ClearBufferDefaultFramebuffer)
3022{
3023 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
3024 constexpr int clearInt[] = {0, 0, 0, 0};
3025 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
3026
3027 // glClear works as usual, this is also a regression test for a bug where we
3028 // iterated on maxDrawBuffers for default framebuffers, triggering an assert
3029 glClear(GL_COLOR_BUFFER_BIT);
3030 EXPECT_GL_NO_ERROR();
3031
3032 // Default framebuffers are normalized uints, so only glClearBufferfv works.
3033 glClearBufferfv(GL_COLOR, 0, clearFloat);
3034 EXPECT_GL_NO_ERROR();
3035
3036 glClearBufferiv(GL_COLOR, 0, clearInt);
3037 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3038
3039 glClearBufferuiv(GL_COLOR, 0, clearUint);
3040 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3041}
3042
Geoff Lange4915782017-04-12 15:19:07 -04003043// Verify that errors are generate when trying to blit from an image to itself
3044TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
3045{
3046 GLTexture textures[2];
3047 glBindTexture(GL_TEXTURE_2D, textures[0]);
3048 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
3049 glBindTexture(GL_TEXTURE_2D, textures[1]);
3050 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
3051
3052 GLRenderbuffer renderbuffers[2];
3053 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
3054 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
3055 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
3056 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
3057
3058 GLFramebuffer framebuffers[2];
3059 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
3060 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
3061
3062 ASSERT_GL_NO_ERROR();
3063
3064 // Same texture
3065 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3066 0);
3067 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3068 0);
3069 ASSERT_GL_NO_ERROR();
3070 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3071 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3072
3073 // Same textures but different renderbuffers
3074 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3075 renderbuffers[0]);
3076 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3077 renderbuffers[1]);
3078 ASSERT_GL_NO_ERROR();
3079 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
3080 ASSERT_GL_NO_ERROR();
3081 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3082 GL_NEAREST);
3083 ASSERT_GL_NO_ERROR();
3084 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
3085 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3086 GL_NEAREST);
3087 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3088
3089 // Same renderbuffers but different textures
3090 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
3091 0);
3092 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
3093 0);
3094 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3095 renderbuffers[0]);
3096 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
3097 renderbuffers[0]);
3098 ASSERT_GL_NO_ERROR();
3099 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
3100 ASSERT_GL_NO_ERROR();
3101 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3102 GL_NEAREST);
3103 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3104 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
3105 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
3106 GL_NEAREST);
3107 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
3108}
3109
Geoff Lange0cff192017-05-30 13:04:56 -04003110// Verify that errors are generated when the fragment shader output doesn't match the bound color
3111// buffer types
3112TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
3113{
3114 const std::string vertexShader =
3115 "#version 300 es\n"
3116 "void main() {\n"
3117 " gl_Position = vec4(0, 0, 0, 1);\n"
3118 "}\n";
3119
3120 const std::string fragmentShader =
3121 "#version 300 es\n"
3122 "precision mediump float;\n"
3123 "layout(location = 0) out vec4 floatOutput;\n"
3124 "layout(location = 1) out uvec4 uintOutput;\n"
3125 "layout(location = 2) out ivec4 intOutput;\n"
3126 "void main() {\n"
3127 " floatOutput = vec4(0, 0, 0, 1);\n"
3128 " uintOutput = uvec4(0, 0, 0, 1);\n"
3129 " intOutput = ivec4(0, 0, 0, 1);\n"
3130 "}\n";
3131
3132 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3133 glUseProgram(program.get());
3134
3135 GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
3136 GLuint uintLocation = glGetFragDataLocation(program, "uintOutput");
3137 GLuint intLocation = glGetFragDataLocation(program, "intOutput");
3138
3139 GLFramebuffer fbo;
3140 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3141
3142 GLRenderbuffer floatRenderbuffer;
3143 glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
3144 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
3145 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
3146 floatRenderbuffer);
3147
3148 GLRenderbuffer uintRenderbuffer;
3149 glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
3150 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
3151 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3152 uintRenderbuffer);
3153
3154 GLRenderbuffer intRenderbuffer;
3155 glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
3156 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
3157 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3158 intRenderbuffer);
3159
3160 ASSERT_GL_NO_ERROR();
3161
3162 GLint maxDrawBuffers = 0;
3163 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3164 std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
3165 drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
3166 drawBuffers[uintLocation] = GL_COLOR_ATTACHMENT0 + uintLocation;
3167 drawBuffers[intLocation] = GL_COLOR_ATTACHMENT0 + intLocation;
3168
3169 glDrawBuffers(maxDrawBuffers, drawBuffers.data());
3170
3171 // Check that the correct case generates no errors
3172 glDrawArrays(GL_TRIANGLES, 0, 6);
3173 EXPECT_GL_NO_ERROR();
3174
3175 // Unbind some buffers and verify that there are still no errors
3176 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3177 0);
3178 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3179 0);
3180 glDrawArrays(GL_TRIANGLES, 0, 6);
3181 EXPECT_GL_NO_ERROR();
3182
3183 // Swap the int and uint buffers to and verify that an error is generated
3184 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3185 intRenderbuffer);
3186 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3187 uintRenderbuffer);
3188 glDrawArrays(GL_TRIANGLES, 0, 6);
3189 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3190
3191 // Swap the float and uint buffers to and verify that an error is generated
3192 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
3193 floatRenderbuffer);
3194 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
3195 uintRenderbuffer);
3196 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
3197 intRenderbuffer);
3198 glDrawArrays(GL_TRIANGLES, 0, 6);
3199 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3200}
3201
Geoff Lang9ab5b822017-05-30 16:19:23 -04003202// Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
3203// types
Corentin Wallezc3bc9842017-10-11 15:15:59 -04003204TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMismatch)
Geoff Lang9ab5b822017-05-30 16:19:23 -04003205{
3206 const std::string vertexShader =
3207 "#version 300 es\n"
3208 "in vec4 floatInput;\n"
3209 "in uvec4 uintInput;\n"
3210 "in ivec4 intInput;\n"
3211 "void main() {\n"
3212 " gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);\n"
3213 "}\n";
3214
3215 const std::string fragmentShader =
3216 "#version 300 es\n"
3217 "precision mediump float;\n"
3218 "out vec4 outputColor;\n"
3219 "void main() {\n"
3220 " outputColor = vec4(0, 0, 0, 1);"
3221 "}\n";
3222
3223 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3224 glUseProgram(program.get());
3225
3226 GLint floatLocation = glGetAttribLocation(program, "floatInput");
3227 GLint uintLocation = glGetAttribLocation(program, "uintInput");
3228 GLint intLocation = glGetAttribLocation(program, "intInput");
3229
3230 // Default attributes are of float types
3231 glDrawArrays(GL_TRIANGLES, 0, 6);
3232 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3233
3234 // Set the default attributes to the correct types, should succeed
3235 glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
3236 glVertexAttribI4i(intLocation, 0, 0, 0, 1);
3237 glDrawArrays(GL_TRIANGLES, 0, 6);
3238 EXPECT_GL_NO_ERROR();
3239
3240 // Change the default float attribute to an integer, should fail
3241 glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
3242 glDrawArrays(GL_TRIANGLES, 0, 6);
3243 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3244
3245 // Use a buffer for some attributes
3246 GLBuffer buffer;
3247 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3248 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
3249 glEnableVertexAttribArray(floatLocation);
3250 glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
3251 glDrawArrays(GL_TRIANGLES, 0, 6);
3252 EXPECT_GL_NO_ERROR();
3253
3254 // Use a float pointer attrib for a uint input
3255 glEnableVertexAttribArray(uintLocation);
3256 glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
3257 glDrawArrays(GL_TRIANGLES, 0, 6);
3258 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3259
3260 // Use a uint pointer for the uint input
3261 glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
3262 glDrawArrays(GL_TRIANGLES, 0, 6);
3263 EXPECT_GL_NO_ERROR();
3264}
3265
Corentin Walleze7557742017-06-01 13:09:57 -04003266// Tests the WebGL removal of undefined behavior when attachments aren't written to.
3267TEST_P(WebGLCompatibilityTest, DrawBuffers)
3268{
Corentin Walleze7557742017-06-01 13:09:57 -04003269 // Make sure we can use at least 4 attachments for the tests.
3270 bool useEXT = false;
3271 if (getClientMajorVersion() < 3)
3272 {
3273 if (!extensionRequestable("GL_EXT_draw_buffers"))
3274 {
3275 std::cout << "Test skipped because draw buffers are not available" << std::endl;
3276 return;
3277 }
3278
3279 glRequestExtensionANGLE("GL_EXT_draw_buffers");
3280 useEXT = true;
3281 EXPECT_GL_NO_ERROR();
3282 }
3283
3284 GLint maxDrawBuffers = 0;
3285 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
3286 if (maxDrawBuffers < 4)
3287 {
3288 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
3289 return;
3290 }
3291
3292 // Clears all the renderbuffers to red.
3293 auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
3294 GLFramebuffer clearFBO;
3295 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, clearFBO);
3296
3297 glClearColor(1, 0, 0, 1);
3298 for (int i = 0; i < 4; ++i)
3299 {
3300 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
3301 renderbuffers[i]);
3302 glClear(GL_COLOR_BUFFER_BIT);
3303 }
3304 ASSERT_GL_NO_ERROR();
3305 };
3306
3307 // Checks that the renderbuffers specified by mask have the correct color
3308 auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
3309 GLFramebuffer readFBO;
3310 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
3311
3312 for (int i = 0; i < 4; ++i)
3313 {
3314 if (mask & (1 << i))
3315 {
3316 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
3317 GL_RENDERBUFFER, renderbuffers[i]);
3318 EXPECT_PIXEL_COLOR_EQ(0, 0, color);
3319 }
3320 }
3321 ASSERT_GL_NO_ERROR();
3322 };
3323
3324 // Depending on whether we are using the extension or ES3, a different entrypoint must be called
3325 auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
3326 if (useEXT)
3327 {
3328 glDrawBuffersEXT(numBuffers, buffers);
3329 }
3330 else
3331 {
3332 glDrawBuffers(numBuffers, buffers);
3333 }
3334 };
3335
3336 // Initialized the test framebuffer
3337 GLFramebuffer drawFBO;
3338 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3339
3340 GLRenderbuffer renderbuffers[4];
3341 for (int i = 0; i < 4; ++i)
3342 {
3343 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
3344 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
3345 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
3346 renderbuffers[i]);
3347 }
3348
3349 ASSERT_GL_NO_ERROR();
3350
3351 const char *vertESSL1 =
3352 "attribute vec4 a_pos;\n"
3353 "void main()\n"
3354 "{\n"
3355 " gl_Position = a_pos;\n"
3356 "}\n";
3357 const char *vertESSL3 =
3358 "#version 300 es\n"
3359 "in vec4 a_pos;\n"
3360 "void main()\n"
3361 "{\n"
3362 " gl_Position = a_pos;\n"
3363 "}\n";
3364
3365 GLenum allDrawBuffers[] = {
3366 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
3367 };
3368
3369 GLenum halfDrawBuffers[] = {
3370 GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
3371 };
3372
3373 // Test that when using gl_FragColor, only the first attachment is written to.
3374 const char *fragESSL1 =
3375 "precision highp float;\n"
3376 "void main()\n"
3377 "{\n"
3378 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
3379 "}\n";
3380 ANGLE_GL_PROGRAM(programESSL1, vertESSL1, fragESSL1);
3381
3382 {
3383 ClearEverythingToRed(renderbuffers);
3384
3385 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3386 DrawBuffers(useEXT, 4, allDrawBuffers);
3387 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
3388 ASSERT_GL_NO_ERROR();
3389
3390 CheckColors(renderbuffers, 0b0001, GLColor::green);
3391 CheckColors(renderbuffers, 0b1110, GLColor::red);
3392 }
3393
3394 // Test that when using gl_FragColor, but the first draw buffer is 0, then no attachment is
3395 // written to.
3396 {
3397 ClearEverythingToRed(renderbuffers);
3398
3399 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3400 DrawBuffers(useEXT, 4, halfDrawBuffers);
3401 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
3402 ASSERT_GL_NO_ERROR();
3403
3404 CheckColors(renderbuffers, 0b1111, GLColor::red);
3405 }
3406
3407 // Test what happens when rendering to a subset of the outputs. There is a behavior difference
3408 // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
3409 // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
3410 // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
3411 // attachments not declared in the shader should not be written to.
3412 const char *writeOddOutputsVert;
3413 const char *writeOddOutputsFrag;
3414 GLColor unwrittenColor;
3415 if (useEXT)
3416 {
3417 // In the extension, when an attachment isn't written to, it should get 0's
3418 unwrittenColor = GLColor(0, 0, 0, 0);
3419 writeOddOutputsVert = vertESSL1;
3420 writeOddOutputsFrag =
3421 "#extension GL_EXT_draw_buffers : require\n"
3422 "precision highp float;\n"
3423 "void main()\n"
3424 "{\n"
3425 " gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3426 " gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3427 "}\n";
3428 }
3429 else
3430 {
3431 // In ES3 if an attachment isn't declared, it shouldn't get written and should be red
3432 // because of the preceding clears.
3433 unwrittenColor = GLColor::red;
3434 writeOddOutputsVert = vertESSL3;
3435 writeOddOutputsFrag =
3436 "#version 300 es\n"
3437 "precision highp float;\n"
3438 "layout(location = 1) out vec4 output1;"
3439 "layout(location = 3) out vec4 output2;"
3440 "void main()\n"
3441 "{\n"
3442 " output1 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3443 " output2 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3444 "}\n";
3445 }
3446 ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
3447
3448 // Test that attachments not written to get the "unwritten" color
3449 {
3450 ClearEverythingToRed(renderbuffers);
3451
3452 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3453 DrawBuffers(useEXT, 4, allDrawBuffers);
3454 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3455 ASSERT_GL_NO_ERROR();
3456
3457 CheckColors(renderbuffers, 0b1010, GLColor::green);
3458 CheckColors(renderbuffers, 0b0101, unwrittenColor);
3459 }
3460
3461 // Test that attachments not written to get the "unwritten" color but that even when the
3462 // extension is used, disabled attachments are not written at all and stay red.
3463 {
3464 ClearEverythingToRed(renderbuffers);
3465
3466 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3467 DrawBuffers(useEXT, 4, halfDrawBuffers);
3468 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3469 ASSERT_GL_NO_ERROR();
3470
3471 CheckColors(renderbuffers, 0b1000, GLColor::green);
3472 CheckColors(renderbuffers, 0b0100, unwrittenColor);
3473 CheckColors(renderbuffers, 0b0011, GLColor::red);
3474 }
3475}
3476
Geoff Lang536eca12017-09-13 11:23:35 -04003477// Test that it's possible to generate mipmaps on unsized floating point textures once the
3478// extensions have been enabled
3479TEST_P(WebGLCompatibilityTest, GenerateMipmapUnsizedFloatingPointTexture)
3480{
3481 if (extensionRequestable("GL_OES_texture_float"))
3482 {
3483 glRequestExtensionANGLE("GL_OES_texture_float");
3484 }
3485 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_texture_float"));
3486
3487 GLTexture texture;
3488 glBindTexture(GL_TEXTURE_2D, texture);
3489
3490 constexpr GLColor32F data[4] = {
3491 kFloatRed, kFloatRed, kFloatGreen, kFloatBlue,
3492 };
3493 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_FLOAT, data);
3494 ASSERT_GL_NO_ERROR();
3495
3496 glGenerateMipmap(GL_TEXTURE_2D);
3497 EXPECT_GL_NO_ERROR();
3498}
3499// Test that it's possible to generate mipmaps on unsized floating point textures once the
3500// extensions have been enabled
3501TEST_P(WebGLCompatibilityTest, GenerateMipmapSizedFloatingPointTexture)
3502{
3503 if (extensionRequestable("GL_OES_texture_float"))
3504 {
3505 glRequestExtensionANGLE("GL_OES_texture_float");
3506 }
3507 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_OES_texture_float"));
3508
3509 if (extensionRequestable("GL_EXT_texture_storage"))
3510 {
3511 glRequestExtensionANGLE("GL_EXT_texture_storage");
3512 }
3513 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_texture_storage"));
3514
3515 GLTexture texture;
3516 glBindTexture(GL_TEXTURE_2D, texture);
3517
3518 constexpr GLColor32F data[4] = {
3519 kFloatRed, kFloatRed, kFloatGreen, kFloatBlue,
3520 };
3521 glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA32F, 2, 2);
3522 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_FLOAT, data);
3523 ASSERT_GL_NO_ERROR();
3524
3525 glGenerateMipmap(GL_TEXTURE_2D);
3526 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3527
3528 if (extensionRequestable("GL_EXT_color_buffer_float"))
3529 {
3530 // Format is renderable but not filterable
3531 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
3532 glGenerateMipmap(GL_TEXTURE_2D);
3533 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3534 }
3535
3536 if (extensionRequestable("GL_EXT_color_buffer_float_linear"))
3537 {
3538 // Format is renderable but not filterable
3539 glRequestExtensionANGLE("GL_EXT_color_buffer_float_linear");
3540
3541 if (extensionEnabled("GL_EXT_color_buffer_float"))
3542 {
3543 // Format is filterable and renderable
3544 glGenerateMipmap(GL_TEXTURE_2D);
3545 EXPECT_GL_NO_ERROR();
3546 }
3547 else
3548 {
3549 // Format is filterable but not renderable
3550 glGenerateMipmap(GL_TEXTURE_2D);
3551 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3552 }
3553 }
3554}
3555
Frank Henigmanfccbac22017-05-28 17:29:26 -04003556// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
3557// qualifiers.
3558TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
3559{
3560 const std::string vertexShader =
3561 "#version 300 es\n"
3562 "uniform Block { mediump vec4 val; };\n"
3563 "void main() { gl_Position = val; }\n";
3564 const std::string fragmentShader =
3565 "#version 300 es\n"
3566 "uniform Block { highp vec4 val; };\n"
3567 "out highp vec4 out_FragColor;\n"
3568 "void main() { out_FragColor = val; }\n";
3569
3570 GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
3571 ASSERT_NE(0u, vs);
3572 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
3573 ASSERT_NE(0u, fs);
3574
3575 GLuint program = glCreateProgram();
3576
3577 glAttachShader(program, vs);
3578 glDeleteShader(vs);
3579 glAttachShader(program, fs);
3580 glDeleteShader(fs);
3581
3582 glLinkProgram(program);
3583 GLint linkStatus;
3584 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
3585 ASSERT_EQ(0, linkStatus);
3586
3587 glDeleteProgram(program);
3588}
3589
Geoff Lang69df2422017-07-05 12:42:31 -04003590// Test no attribute vertex shaders
3591TEST_P(WebGL2CompatibilityTest, NoAttributeVertexShader)
3592{
3593 const std::string vertexShader =
3594 "#version 300 es\n"
3595 "void main()\n"
3596 "{\n"
3597 "\n"
3598 " ivec2 xy = ivec2(gl_VertexID % 2, (gl_VertexID / 2 + gl_VertexID / 3) % 2);\n"
3599 " gl_Position = vec4(vec2(xy) * 2. - 1., 0, 1);\n"
3600 "}";
3601 const std::string fragmentShader =
3602 "#version 300 es\n"
3603 "precision mediump float;\n"
3604 "out vec4 result;\n"
3605 "void main()\n"
3606 "{\n"
3607 " result = vec4(0, 1, 0, 1);\n"
3608 "}";
3609
3610 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3611 glUseProgram(program);
3612
3613 glDrawArrays(GL_TRIANGLES, 0, 6);
3614 ASSERT_GL_NO_ERROR();
3615 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3616}
3617
Brandon Jonesed5b46f2017-07-21 08:39:17 -07003618// Tests bindAttribLocations for length limit
3619TEST_P(WebGL2CompatibilityTest, BindAttribLocationLimitation)
3620{
3621 constexpr int maxLocStringLength = 1024;
3622 const std::string tooLongString(maxLocStringLength + 1, '_');
3623
3624 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
3625
3626 EXPECT_GL_ERROR(GL_INVALID_VALUE);
3627}
3628
Geoff Langc287ea62016-09-16 14:46:51 -04003629// Use this to select which configurations (e.g. which renderer, which GLES major version) these
3630// tests should be run against.
3631ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
3632 ES2_D3D9(),
3633 ES2_D3D11(),
3634 ES3_D3D11(),
Geoff Langc287ea62016-09-16 14:46:51 -04003635 ES2_OPENGL(),
3636 ES3_OPENGL(),
3637 ES2_OPENGLES(),
3638 ES3_OPENGLES());
3639
Jamie Madill07be8bf2017-02-02 19:59:57 -05003640ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Geoff Langc287ea62016-09-16 14:46:51 -04003641} // namespace