blob: 4f799a1bce4b14ca4f3ba07a215fcba27c79826c [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 Langa0e0aeb2017-04-12 15:06:29 -0400555// Verify that the context generates the correct error when the framebuffer attachments are
556// different sizes
557TEST_P(WebGLCompatibilityTest, FramebufferAttachmentSizeMissmatch)
558{
559 GLFramebuffer fbo;
560 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
561
562 GLTexture textures[2];
563 glBindTexture(GL_TEXTURE_2D, textures[0]);
564 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
565 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
566
567 ASSERT_GL_NO_ERROR();
568 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
569
570 GLRenderbuffer renderbuffer;
571 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
572 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 3, 3);
573 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
574
575 ASSERT_GL_NO_ERROR();
576 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
577 glCheckFramebufferStatus(GL_FRAMEBUFFER));
578
579 if (extensionRequestable("GL_EXT_draw_buffers"))
580 {
581 glRequestExtensionANGLE("GL_EXT_draw_buffers");
582 EXPECT_GL_NO_ERROR();
583 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
584
585 glBindTexture(GL_TEXTURE_2D, textures[1]);
586 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
587 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
588 ASSERT_GL_NO_ERROR();
589
590 ASSERT_GL_NO_ERROR();
591 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
592 glCheckFramebufferStatus(GL_FRAMEBUFFER));
593
594 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
595
596 ASSERT_GL_NO_ERROR();
597 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
598
599 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
600
601 ASSERT_GL_NO_ERROR();
602 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
603 glCheckFramebufferStatus(GL_FRAMEBUFFER));
604 }
605}
606
Corentin Wallez327411e2016-12-09 11:09:17 -0500607// Test that client-side array buffers are forbidden in WebGL mode
608TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
609{
610 const std::string &vert =
611 "attribute vec3 a_pos;\n"
612 "void main()\n"
613 "{\n"
614 " gl_Position = vec4(a_pos, 1.0);\n"
615 "}\n";
616
617 const std::string &frag =
618 "precision highp float;\n"
619 "void main()\n"
620 "{\n"
621 " gl_FragColor = vec4(1.0);\n"
622 "}\n";
623
624 ANGLE_GL_PROGRAM(program, vert, frag);
625
626 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
627 ASSERT_NE(-1, posLocation);
628 glUseProgram(program.get());
629
630 const auto &vertices = GetQuadVertices();
Corentin Wallezfd456442016-12-21 17:57:00 -0500631 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
Corentin Wallez327411e2016-12-09 11:09:17 -0500632 glEnableVertexAttribArray(posLocation);
633
634 ASSERT_GL_NO_ERROR();
635 glDrawArrays(GL_TRIANGLES, 0, 6);
636 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
637}
638
639// Test that client-side element array buffers are forbidden in WebGL mode
640TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
641{
642 const std::string &vert =
643 "attribute vec3 a_pos;\n"
644 "void main()\n"
645 "{\n"
646 " gl_Position = vec4(a_pos, 1.0);\n"
647 "}\n";
648
649 const std::string &frag =
650 "precision highp float;\n"
651 "void main()\n"
652 "{\n"
653 " gl_FragColor = vec4(1.0);\n"
654 "}\n";
655
656 ANGLE_GL_PROGRAM(program, vert, frag);
657
658 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
659 ASSERT_NE(-1, posLocation);
660 glUseProgram(program.get());
661
662 const auto &vertices = GetQuadVertices();
663
664 GLBuffer vertexBuffer;
665 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
666 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
667 GL_STATIC_DRAW);
668
669 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
670 glEnableVertexAttribArray(posLocation);
671
Corentin Wallez327411e2016-12-09 11:09:17 -0500672 ASSERT_GL_NO_ERROR();
Corentin Wallezded1b5a2017-03-09 18:58:48 -0500673
674 // Use the pointer with value of 1 for indices instead of an actual pointer because WebGL also
675 // enforces that the top bit of indices must be 0 (i.e. offset >= 0) and would generate
676 // GL_INVALID_VALUE in that case. Using a null pointer gets caught by another check.
677 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void*>(intptr_t(1)));
Corentin Wallez327411e2016-12-09 11:09:17 -0500678 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
679}
680
Corentin Wallez672f7f32017-06-15 17:42:17 -0400681// Test that client-side array buffers are forbidden even if the program doesn't use the attribute
682TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBufferEvenNotUsedOnes)
683{
684 const std::string &vert =
685 "void main()\n"
686 "{\n"
687 " gl_Position = vec4(1.0);\n"
688 "}\n";
689
690 const std::string &frag =
691 "precision highp float;\n"
692 "void main()\n"
693 "{\n"
694 " gl_FragColor = vec4(1.0);\n"
695 "}\n";
696
697 ANGLE_GL_PROGRAM(program, vert, frag);
698
699 glUseProgram(program.get());
700
701 const auto &vertices = GetQuadVertices();
702 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
703 glEnableVertexAttribArray(0);
704
705 ASSERT_GL_NO_ERROR();
706 glDrawArrays(GL_TRIANGLES, 0, 6);
707 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
708}
709
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500710// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
711TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
712{
713 // Run the test in an FBO to make sure we have some stencil bits.
714 GLRenderbuffer renderbuffer;
715 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
716 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
717
718 GLFramebuffer framebuffer;
719 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
720 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
721 renderbuffer.get());
722
723 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
724 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
725 glUseProgram(program.get());
726 ASSERT_GL_NO_ERROR();
727
728 // Having ref and mask the same for front and back is valid.
729 glStencilMask(255);
730 glStencilFunc(GL_ALWAYS, 0, 255);
731 glDrawArrays(GL_TRIANGLES, 0, 6);
732 ASSERT_GL_NO_ERROR();
733
734 // Having a different front - back write mask generates an error.
735 glStencilMaskSeparate(GL_FRONT, 1);
736 glDrawArrays(GL_TRIANGLES, 0, 6);
737 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
738
739 // Setting both write masks separately to the same value is valid.
740 glStencilMaskSeparate(GL_BACK, 1);
741 glDrawArrays(GL_TRIANGLES, 0, 6);
742 ASSERT_GL_NO_ERROR();
743
744 // Having a different stencil front - back mask generates an error
745 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
746 glDrawArrays(GL_TRIANGLES, 0, 6);
747 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
748
749 // Setting both masks separately to the same value is valid.
750 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
751 glDrawArrays(GL_TRIANGLES, 0, 6);
752 ASSERT_GL_NO_ERROR();
753
754 // Having a different stencil front - back reference generates an error
755 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
756 glDrawArrays(GL_TRIANGLES, 0, 6);
757 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
758
759 // Setting both references separately to the same value is valid.
760 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
761 glDrawArrays(GL_TRIANGLES, 0, 6);
762 ASSERT_GL_NO_ERROR();
763
764 // Using different stencil funcs, everything being equal is valid.
765 glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
766 glDrawArrays(GL_TRIANGLES, 0, 6);
767 ASSERT_GL_NO_ERROR();
768}
769
Corentin Wallez506fc9c2016-12-21 16:53:33 -0500770// Test that GL_FIXED is forbidden
771TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
772{
773 GLBuffer buffer;
774 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
775 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
776
777 glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
778 ASSERT_GL_NO_ERROR();
779
780 glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
781 EXPECT_GL_ERROR(GL_INVALID_ENUM);
782}
783
784// Test the WebGL limit of 255 for the attribute stride
785TEST_P(WebGLCompatibilityTest, MaxStride)
786{
787 GLBuffer buffer;
788 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
789 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
790
791 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
792 ASSERT_GL_NO_ERROR();
793
794 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
795 EXPECT_GL_ERROR(GL_INVALID_VALUE);
796}
797
Corentin Wallezfd456442016-12-21 17:57:00 -0500798// Test the checks for OOB reads in the vertex buffers, non-instanced version
799TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
800{
801 const std::string &vert =
802 "attribute float a_pos;\n"
803 "void main()\n"
804 "{\n"
805 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
806 "}\n";
807
808 const std::string &frag =
809 "precision highp float;\n"
810 "void main()\n"
811 "{\n"
812 " gl_FragColor = vec4(1.0);\n"
813 "}\n";
814
815 ANGLE_GL_PROGRAM(program, vert, frag);
816
817 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
818 ASSERT_NE(-1, posLocation);
819 glUseProgram(program.get());
820
821 GLBuffer buffer;
822 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
823 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
824
825 glEnableVertexAttribArray(posLocation);
826
827 const uint8_t* zeroOffset = nullptr;
828
829 // Test touching the last element is valid.
830 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
831 glDrawArrays(GL_POINTS, 0, 4);
832 ASSERT_GL_NO_ERROR();
833
834 // Test touching the last element + 1 is invalid.
835 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
836 glDrawArrays(GL_POINTS, 0, 4);
837 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
838
839 // Test touching the last element is valid, using a stride.
840 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
841 glDrawArrays(GL_POINTS, 0, 4);
842 ASSERT_GL_NO_ERROR();
843
844 // Test touching the last element + 1 is invalid, using a stride.
845 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
846 glDrawArrays(GL_POINTS, 0, 4);
847 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
848
849 // Test any offset is valid if no vertices are drawn.
850 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
851 glDrawArrays(GL_POINTS, 0, 0);
852 ASSERT_GL_NO_ERROR();
853}
854
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500855// Test the checks for OOB reads in the index buffer
856TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
Geoff Lang5f319a42017-01-09 16:49:19 -0500857{
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500858 const std::string &vert =
859 "attribute float a_pos;\n"
860 "void main()\n"
861 "{\n"
862 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
863 "}\n";
Geoff Lang5f319a42017-01-09 16:49:19 -0500864
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500865 const std::string &frag =
866 "precision highp float;\n"
867 "void main()\n"
868 "{\n"
869 " gl_FragColor = vec4(1.0);\n"
870 "}\n";
871
872 ANGLE_GL_PROGRAM(program, vert, frag);
873
874 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
875 ASSERT_NE(-1, posLocation);
876 glUseProgram(program.get());
877
878 GLBuffer vertexBuffer;
879 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
880 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
881
882 glEnableVertexAttribArray(posLocation);
883
884 const uint8_t *zeroOffset = nullptr;
885 const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
886
887 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset);
888
889 GLBuffer indexBuffer;
890 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
891 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
Geoff Lang5f319a42017-01-09 16:49:19 -0500892 ASSERT_GL_NO_ERROR();
893
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500894 // Test touching the last index is valid
895 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
896 ASSERT_GL_NO_ERROR();
Geoff Lang5f319a42017-01-09 16:49:19 -0500897
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500898 // Test touching the last + 1 element is invalid
899 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
900 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang5f319a42017-01-09 16:49:19 -0500901
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500902 // Test any offset if valid if count is zero
903 glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
904 ASSERT_GL_NO_ERROR();
Corentin Wallezfe9306a2017-02-01 17:41:05 -0500905
906 // Test touching the first index is valid
907 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
908 ASSERT_GL_NO_ERROR();
909
910 // Test touching the first - 1 index is invalid
911 // The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
912 // the historic behavior of WebGL implementations
913 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset - 1);
914 EXPECT_GL_ERROR(GL_INVALID_VALUE);
Geoff Lang5f319a42017-01-09 16:49:19 -0500915}
916
Frank Henigman6137ddc2017-02-10 18:55:07 -0500917// Test depth range with 'near' more or less than 'far.'
918TEST_P(WebGLCompatibilityTest, DepthRange)
919{
920 glDepthRangef(0, 1);
921 ASSERT_GL_NO_ERROR();
922
923 glDepthRangef(.5, .5);
924 ASSERT_GL_NO_ERROR();
925
926 glDepthRangef(1, 0);
927 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
928}
929
Frank Henigman146e8a12017-03-02 23:22:37 -0500930// Test all blend function combinations.
931// In WebGL it is invalid to combine constant color with constant alpha.
932TEST_P(WebGLCompatibilityTest, BlendWithConstantColor)
933{
934 constexpr GLenum srcFunc[] = {
935 GL_ZERO,
936 GL_ONE,
937 GL_SRC_COLOR,
938 GL_ONE_MINUS_SRC_COLOR,
939 GL_DST_COLOR,
940 GL_ONE_MINUS_DST_COLOR,
941 GL_SRC_ALPHA,
942 GL_ONE_MINUS_SRC_ALPHA,
943 GL_DST_ALPHA,
944 GL_ONE_MINUS_DST_ALPHA,
945 GL_CONSTANT_COLOR,
946 GL_ONE_MINUS_CONSTANT_COLOR,
947 GL_CONSTANT_ALPHA,
948 GL_ONE_MINUS_CONSTANT_ALPHA,
949 GL_SRC_ALPHA_SATURATE,
950 };
951
952 constexpr GLenum dstFunc[] = {
953 GL_ZERO, GL_ONE,
954 GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
955 GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
956 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
957 GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA,
958 GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
959 GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA,
960 };
961
962 for (GLenum src : srcFunc)
963 {
964 for (GLenum dst : dstFunc)
965 {
966 glBlendFunc(src, dst);
967 CheckBlendFunctions(src, dst);
968 glBlendFuncSeparate(src, dst, GL_ONE, GL_ONE);
969 CheckBlendFunctions(src, dst);
970 }
971 }
972}
973
Geoff Langfc32e8b2017-05-31 14:16:59 -0400974// Test that binding/querying uniforms and attributes with invalid names generates errors
975TEST_P(WebGLCompatibilityTest, InvalidAttributeAndUniformNames)
976{
977 const std::string validAttribName =
978 "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
979 const std::string validUniformName =
980 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
Geoff Langa71a98e2017-06-19 15:15:00 -0400981 std::vector<char> invalidSet = {'"', '$', '`', '@', '\''};
982 if (getClientMajorVersion() < 3)
983 {
984 invalidSet.push_back('\\');
985 }
Geoff Langfc32e8b2017-05-31 14:16:59 -0400986
987 std::string vert = "attribute float ";
988 vert += validAttribName;
989 vert +=
990 ";\n"
991 "void main()\n"
992 "{\n"
993 " gl_Position = vec4(1.0);\n"
994 "}\n";
995
996 std::string frag =
997 "precision highp float;\n"
998 "uniform vec4 ";
999 frag += validUniformName;
Geoff Langcab92ee2017-07-19 17:32:07 -04001000 // Insert illegal characters into comments
Geoff Langfc32e8b2017-05-31 14:16:59 -04001001 frag +=
1002 ";\n"
Geoff Langcab92ee2017-07-19 17:32:07 -04001003 " // $ \" @ /*\n"
Geoff Langfc32e8b2017-05-31 14:16:59 -04001004 "void main()\n"
Geoff Langcab92ee2017-07-19 17:32:07 -04001005 "{/*\n"
1006 " ` @ $\n"
1007 " */gl_FragColor = vec4(1.0);\n"
Geoff Langfc32e8b2017-05-31 14:16:59 -04001008 "}\n";
1009
1010 ANGLE_GL_PROGRAM(program, vert, frag);
1011 EXPECT_GL_NO_ERROR();
1012
1013 for (char invalidChar : invalidSet)
1014 {
1015 std::string invalidName = validAttribName + invalidChar;
1016 glGetAttribLocation(program, invalidName.c_str());
1017 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1018 << "glGetAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1019
1020 glBindAttribLocation(program, 0, invalidName.c_str());
1021 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1022 << "glBindAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1023 }
1024
1025 for (char invalidChar : invalidSet)
1026 {
1027 std::string invalidName = validUniformName + invalidChar;
1028 glGetUniformLocation(program, invalidName.c_str());
1029 EXPECT_GL_ERROR(GL_INVALID_VALUE)
1030 << "glGetUniformLocation unexpectedly succeeded for name \"" << invalidName << "\".";
1031 }
1032
1033 for (char invalidChar : invalidSet)
1034 {
1035 std::string invalidAttribName = validAttribName + invalidChar;
1036 const char *invalidVert[] = {
1037 "attribute float ",
1038 invalidAttribName.c_str(),
1039 ";\n",
1040 "void main()\n",
1041 "{\n",
1042 " gl_Position = vec4(1.0);\n",
1043 "}\n",
1044 };
1045
1046 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1047 glShaderSource(shader, static_cast<GLsizei>(ArraySize(invalidVert)), invalidVert, nullptr);
1048 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1049 glDeleteShader(shader);
1050 }
1051}
1052
Geoff Langcab92ee2017-07-19 17:32:07 -04001053// Test that line continuation is handled correctly when valdiating shader source
1054TEST_P(WebGL2CompatibilityTest, ShaderSourceLineContinuation)
1055{
1056 const char *validVert =
1057 "#version 300 es\n"
1058 "precision mediump float;\n"
1059 "\n"
1060 "void main ()\n"
1061 "{\n"
1062 " float f\\\n"
1063 "oo = 1.0;\n"
1064 " gl_Position = vec4(foo);\n"
1065 "}\n";
1066
1067 const char *invalidVert =
1068 "#version 300 es\n"
1069 "precision mediump float;\n"
1070 "\n"
1071 "void main ()\n"
1072 "{\n"
1073 " float f\\$\n"
1074 "oo = 1.0;\n"
1075 " gl_Position = vec4(foo);\n"
1076 "}\n";
1077
1078 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
1079 glShaderSource(shader, 1, &validVert, nullptr);
1080 EXPECT_GL_NO_ERROR();
1081 glShaderSource(shader, 1, &invalidVert, nullptr);
1082 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1083 glDeleteShader(shader);
1084}
1085
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001086// Tests bindAttribLocations for reserved prefixes and length limits
1087TEST_P(WebGLCompatibilityTest, BindAttribLocationLimitation)
1088{
1089 constexpr int maxLocStringLength = 256;
1090 const std::string tooLongString(maxLocStringLength + 1, '_');
1091
1092 glBindAttribLocation(0, 0, "_webgl_var");
1093
1094 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1095
1096 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
1097
1098 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1099}
1100
Corentin Wallezfd456442016-12-21 17:57:00 -05001101// Test the checks for OOB reads in the vertex buffers, instanced version
1102TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
1103{
1104 const std::string &vert =
1105 "attribute float a_pos;\n"
Geoff Lang407d4e72017-04-12 14:54:11 -04001106 "attribute float a_w;\n"
Corentin Wallezfd456442016-12-21 17:57:00 -05001107 "void main()\n"
1108 "{\n"
Geoff Lang407d4e72017-04-12 14:54:11 -04001109 " gl_Position = vec4(a_pos, a_pos, a_pos, a_w);\n"
Corentin Wallezfd456442016-12-21 17:57:00 -05001110 "}\n";
1111
1112 const std::string &frag =
1113 "precision highp float;\n"
1114 "void main()\n"
1115 "{\n"
1116 " gl_FragColor = vec4(1.0);\n"
1117 "}\n";
1118
1119 ANGLE_GL_PROGRAM(program, vert, frag);
1120
1121 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1122 ASSERT_NE(-1, posLocation);
Geoff Lang407d4e72017-04-12 14:54:11 -04001123
1124 GLint wLocation = glGetAttribLocation(program.get(), "a_w");
1125 ASSERT_NE(-1, wLocation);
1126
Corentin Wallezfd456442016-12-21 17:57:00 -05001127 glUseProgram(program.get());
1128
1129 GLBuffer buffer;
1130 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1131 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1132
1133 glEnableVertexAttribArray(posLocation);
1134 glVertexAttribDivisor(posLocation, 1);
1135
Geoff Lang407d4e72017-04-12 14:54:11 -04001136 glEnableVertexAttribArray(wLocation);
1137 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1138 glVertexAttribDivisor(wLocation, 0);
1139
Corentin Wallezfd456442016-12-21 17:57:00 -05001140 const uint8_t* zeroOffset = nullptr;
1141
1142 // Test touching the last element is valid.
1143 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
1144 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1145 ASSERT_GL_NO_ERROR();
1146
1147 // Test touching the last element + 1 is invalid.
1148 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
1149 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1150 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1151
1152 // Test touching the last element is valid, using a stride.
1153 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
1154 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1155 ASSERT_GL_NO_ERROR();
1156
1157 // Test touching the last element + 1 is invalid, using a stride.
1158 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1159 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1160 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1161
1162 // Test any offset is valid if no vertices are drawn.
1163 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1164 glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
1165 ASSERT_GL_NO_ERROR();
1166}
1167
Corentin Wallez0dc97812017-06-22 14:38:44 -04001168// Test that having no attributes with a zero divisor is valid in WebGL2
Geoff Lang407d4e72017-04-12 14:54:11 -04001169TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
1170{
1171 const std::string &vert =
1172 "attribute float a_pos;\n"
1173 "void main()\n"
1174 "{\n"
1175 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1176 "}\n";
1177
1178 const std::string &frag =
1179 "precision highp float;\n"
1180 "void main()\n"
1181 "{\n"
1182 " gl_FragColor = vec4(1.0);\n"
1183 "}\n";
1184
1185 ANGLE_GL_PROGRAM(program, vert, frag);
1186
1187 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1188 ASSERT_NE(-1, posLocation);
1189
1190 glUseProgram(program.get());
1191
1192 GLBuffer buffer;
1193 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1194 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1195
1196 glEnableVertexAttribArray(posLocation);
1197 glVertexAttribDivisor(posLocation, 1);
1198
Geoff Lang407d4e72017-04-12 14:54:11 -04001199 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1200 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
Geoff Lang407d4e72017-04-12 14:54:11 -04001201 ASSERT_GL_NO_ERROR();
1202}
1203
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001204// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
1205TEST_P(WebGLCompatibilityTest, NPOT)
1206{
1207 EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
1208
1209 // Create a texture and set an NPOT mip 0, should always be acceptable.
1210 GLTexture texture;
1211 glBindTexture(GL_TEXTURE_2D, texture.get());
1212 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1213 ASSERT_GL_NO_ERROR();
1214
1215 // Try setting an NPOT mip 1 and verify the error if WebGL 1
1216 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1217 if (getClientMajorVersion() < 3)
1218 {
1219 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1220 }
1221 else
1222 {
1223 ASSERT_GL_NO_ERROR();
1224 }
1225
1226 if (extensionRequestable("GL_OES_texture_npot"))
1227 {
1228 glRequestExtensionANGLE("GL_OES_texture_npot");
1229 ASSERT_GL_NO_ERROR();
1230
1231 // Try again to set NPOT mip 1
1232 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1233 ASSERT_GL_NO_ERROR();
1234 }
1235}
1236
Jamie Madillcad97ee2017-02-02 18:52:44 -05001237template <typename T>
1238void FillTexture2D(GLuint texture,
1239 GLsizei width,
1240 GLsizei height,
1241 const T &onePixelData,
1242 GLint level,
1243 GLint internalFormat,
1244 GLenum format,
1245 GLenum type)
1246{
1247 std::vector<T> allPixelsData(width * height, onePixelData);
1248
1249 glBindTexture(GL_TEXTURE_2D, texture);
1250 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
1251 allPixelsData.data());
1252 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1253 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1254 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1255 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1256}
1257
Frank Henigman875bbba2017-02-08 16:38:17 -05001258// Test that unset gl_Position defaults to (0,0,0,0).
1259TEST_P(WebGLCompatibilityTest, DefaultPosition)
1260{
1261 // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
1262 // and green otherwise. The center of each quadrant will be red if and only if all
1263 // four corners are red.
1264 const std::string vertexShader =
1265 "attribute vec3 pos;\n"
1266 "varying vec4 color;\n"
1267 "void main() {\n"
1268 " if (gl_Position == vec4(0,0,0,0)) {\n"
1269 " color = vec4(1,0,0,1);\n"
1270 " } else {\n"
1271 " color = vec4(0,1,0,1);\n"
1272 " }\n"
1273 " gl_Position = vec4(pos,1);\n"
1274 "}\n";
1275
1276 const std::string fragmentShader =
1277 "precision mediump float;\n"
1278 "varying vec4 color;\n"
1279 "void main() {\n"
1280 " gl_FragColor = color;\n"
1281 "}\n";
1282
1283 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1284 drawQuad(program.get(), "pos", 0.0f, 1.0f, true);
1285 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1286 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1287 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1288 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1289}
1290
Jamie Madilla4595b82017-01-11 17:36:34 -05001291// Tests that a rendering feedback loop triggers a GL error under WebGL.
1292// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
1293TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
1294{
1295 const std::string vertexShader =
1296 "attribute vec4 a_position;\n"
1297 "varying vec2 v_texCoord;\n"
1298 "void main() {\n"
1299 " gl_Position = a_position;\n"
1300 " v_texCoord = (a_position.xy * 0.5) + 0.5;\n"
1301 "}\n";
1302
1303 const std::string fragmentShader =
1304 "precision mediump float;\n"
1305 "varying vec2 v_texCoord;\n"
1306 "uniform sampler2D u_texture;\n"
1307 "void main() {\n"
1308 " // Shader swizzles color channels so we can tell if the draw succeeded.\n"
1309 " gl_FragColor = texture2D(u_texture, v_texCoord).gbra;\n"
1310 "}\n";
1311
1312 GLTexture texture;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001313 FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001314
1315 ASSERT_GL_NO_ERROR();
1316
1317 GLFramebuffer framebuffer;
1318 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1319 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1320
1321 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1322
1323 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1324
1325 GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
1326 ASSERT_NE(-1, uniformLoc);
1327
1328 glUseProgram(program.get());
1329 glUniform1i(uniformLoc, 0);
1330 glDisable(GL_BLEND);
1331 glDisable(GL_DEPTH_TEST);
1332 ASSERT_GL_NO_ERROR();
1333
1334 // Drawing with a texture that is also bound to the current framebuffer should fail
1335 glBindTexture(GL_TEXTURE_2D, texture.get());
1336 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1337 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1338
1339 // Ensure that the texture contents did not change after the previous render
1340 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1341 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1342 ASSERT_GL_NO_ERROR();
1343 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1344
1345 // Drawing when texture is bound to an inactive uniform should succeed
1346 GLTexture texture2;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001347 FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001348
1349 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1350 glActiveTexture(GL_TEXTURE1);
1351 glBindTexture(GL_TEXTURE_2D, texture.get());
1352 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1353 ASSERT_GL_NO_ERROR();
1354 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1355}
1356
Bryan Bernhart58806562017-01-05 13:09:31 -08001357// Test for the max draw buffers and color attachments.
1358TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
1359{
1360 // This test only applies to ES2.
1361 if (getClientMajorVersion() != 2)
1362 {
1363 return;
1364 }
1365
1366 GLFramebuffer fbo[2];
1367 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
1368
1369 // Test that is valid when we bind with a single attachment point.
1370 GLTexture texture;
1371 glBindTexture(GL_TEXTURE_2D, texture.get());
1372 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1373 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1374 ASSERT_GL_NO_ERROR();
1375
1376 // Test that enabling the draw buffers extension will allow us to bind with a non-zero
1377 // attachment point.
1378 if (extensionRequestable("GL_EXT_draw_buffers"))
1379 {
1380 glRequestExtensionANGLE("GL_EXT_draw_buffers");
1381 EXPECT_GL_NO_ERROR();
1382 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
1383
1384 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
1385
1386 GLTexture texture2;
1387 glBindTexture(GL_TEXTURE_2D, texture2.get());
1388 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1389 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
1390 0);
1391 ASSERT_GL_NO_ERROR();
1392 }
1393}
1394
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001395// Test that the offset in the index buffer is forced to be a multiple of the element size
1396TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
1397{
1398 const std::string &vert =
1399 "attribute vec3 a_pos;\n"
1400 "void main()\n"
1401 "{\n"
1402 " gl_Position = vec4(a_pos, 1.0);\n"
1403 "}\n";
1404
1405 const std::string &frag =
1406 "precision highp float;\n"
1407 "void main()\n"
1408 "{\n"
1409 " gl_FragColor = vec4(1.0);\n"
1410 "}\n";
1411
1412 ANGLE_GL_PROGRAM(program, vert, frag);
1413
1414 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1415 ASSERT_NE(-1, posLocation);
1416 glUseProgram(program.get());
1417
1418 const auto &vertices = GetQuadVertices();
1419
1420 GLBuffer vertexBuffer;
1421 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1422 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1423 GL_STATIC_DRAW);
1424
1425 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1426 glEnableVertexAttribArray(posLocation);
1427
1428 GLBuffer indexBuffer;
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001429 const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0, 0};
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001430 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1431 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
1432
1433 ASSERT_GL_NO_ERROR();
1434
1435 const char *zeroIndices = nullptr;
1436
1437 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
1438 ASSERT_GL_NO_ERROR();
1439
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001440 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001441 ASSERT_GL_NO_ERROR();
1442
Brandon Jonesed5b46f2017-07-21 08:39:17 -07001443 glDrawElements(GL_TRIANGLES, 4, GL_UNSIGNED_SHORT, zeroIndices + 1);
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001444 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1445}
1446
1447// Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
1448// size
1449TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
1450{
1451 const char *zeroOffset = nullptr;
1452
1453 // Base case, vector of two floats
1454 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
1455 ASSERT_GL_NO_ERROR();
1456
1457 // Test setting a non-multiple offset
1458 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
1459 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1460 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
1461 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1462 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
1463 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1464
1465 // Test setting a non-multiple stride
1466 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
1467 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1468 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
1469 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1470 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
1471 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1472}
1473
Jamie Madillcad97ee2017-02-02 18:52:44 -05001474void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
1475 const std::array<GLenum, 2> &drawBuffers,
1476 GLenum expectedError)
1477{
1478 glDrawBuffersEXT(2, drawBuffers.data());
1479
1480 // Make sure framebuffer is complete before feedback loop detection
1481 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1482
1483 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
1484
1485 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
1486 // it should be NO_ERROR"
1487 EXPECT_GL_ERROR(expectedError);
1488}
1489
1490// This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
1491// Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
1492TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
1493{
1494 const std::string vertexShader =
1495 "attribute vec4 aPosition;\n"
1496 "varying vec2 texCoord;\n"
1497 "void main() {\n"
1498 " gl_Position = aPosition;\n"
1499 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
1500 "}\n";
1501
1502 const std::string fragmentShader =
1503 "#extension GL_EXT_draw_buffers : require\n"
1504 "precision mediump float;\n"
1505 "uniform sampler2D tex;\n"
1506 "varying vec2 texCoord;\n"
1507 "void main() {\n"
1508 " gl_FragData[0] = texture2D(tex, texCoord);\n"
1509 " gl_FragData[1] = texture2D(tex, texCoord);\n"
1510 "}\n";
1511
1512 GLsizei width = 8;
1513 GLsizei height = 8;
1514
1515 // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
1516 // extension and gl_FragData semantics are changed to enforce indexing by zero always.
1517 // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
1518 if (/*!extensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
1519 {
1520 // No WEBGL_draw_buffers support -- this is legal.
1521 return;
1522 }
1523
1524 GLint maxDrawBuffers = 0;
1525 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1526
1527 if (maxDrawBuffers < 2)
1528 {
1529 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
1530 return;
1531 }
1532
1533 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1534 glUseProgram(program.get());
1535 glViewport(0, 0, width, height);
1536
1537 GLTexture tex0;
1538 GLTexture tex1;
1539 GLFramebuffer fbo;
1540 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1541 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1542 ASSERT_GL_NO_ERROR();
1543
1544 glBindTexture(GL_TEXTURE_2D, tex1.get());
1545 GLint texLoc = glGetUniformLocation(program.get(), "tex");
1546 ASSERT_NE(-1, texLoc);
1547 glUniform1i(texLoc, 0);
1548 ASSERT_GL_NO_ERROR();
1549
1550 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
1551 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
1552 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
1553 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
1554
1555 drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
1556 GL_INVALID_OPERATION);
1557 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
1558 GL_INVALID_OPERATION);
1559 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
1560}
1561
Jamie Madill07be8bf2017-02-02 19:59:57 -05001562// Test tests that texture copying feedback loops are properly rejected in WebGL.
1563// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
1564TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
1565{
1566 GLTexture texture;
1567 glBindTexture(GL_TEXTURE_2D, texture.get());
1568 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1569 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1570 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1571 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1572 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1573
1574 GLTexture texture2;
1575 glBindTexture(GL_TEXTURE_2D, texture2.get());
1576 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1577 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1578 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1579 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1580 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1581
1582 GLFramebuffer framebuffer;
1583 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1584 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1585
1586 // framebuffer should be FRAMEBUFFER_COMPLETE.
1587 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1588 ASSERT_GL_NO_ERROR();
1589
1590 // testing copyTexImage2D
1591
1592 // copyTexImage2D to same texture but different level
1593 glBindTexture(GL_TEXTURE_2D, texture.get());
1594 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
1595 EXPECT_GL_NO_ERROR();
1596
1597 // copyTexImage2D to same texture same level, invalid feedback loop
1598 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
1599 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1600
1601 // copyTexImage2D to different texture
1602 glBindTexture(GL_TEXTURE_2D, texture2.get());
1603 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
1604 EXPECT_GL_NO_ERROR();
1605
1606 // testing copyTexSubImage2D
1607
1608 // copyTexSubImage2D to same texture but different level
1609 glBindTexture(GL_TEXTURE_2D, texture.get());
1610 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
1611 EXPECT_GL_NO_ERROR();
1612
1613 // copyTexSubImage2D to same texture same level, invalid feedback loop
1614 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
1615 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1616
1617 // copyTexSubImage2D to different texture
1618 glBindTexture(GL_TEXTURE_2D, texture2.get());
1619 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
1620 EXPECT_GL_NO_ERROR();
1621}
1622
1623void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
1624 const std::array<GLenum, 2> &drawBuffers,
1625 GLenum expectedError)
1626{
1627 glDrawBuffers(2, drawBuffers.data());
1628
1629 // Make sure framebuffer is complete before feedback loop detection
1630 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1631
1632 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
1633
1634 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
1635 // it should be NO_ERROR"
1636 EXPECT_GL_ERROR(expectedError);
1637}
1638
Yuly Novikov817232e2017-02-22 18:36:10 -05001639// Tests invariance matching rules between built in varyings.
1640// Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
1641TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
1642{
1643 const std::string vertexShaderVariant =
1644 "varying vec4 v_varying;\n"
1645 "void main()\n"
1646 "{\n"
1647 " gl_PointSize = 1.0;\n"
1648 " gl_Position = v_varying;\n"
1649 "}";
1650 const std::string fragmentShaderInvariantGlFragCoord =
1651 "invariant gl_FragCoord;\n"
1652 "void main()\n"
1653 "{\n"
1654 " gl_FragColor = gl_FragCoord;\n"
1655 "}";
1656 const std::string fragmentShaderInvariantGlPointCoord =
1657 "invariant gl_PointCoord;\n"
1658 "void main()\n"
1659 "{\n"
1660 " gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);\n"
1661 "}";
1662
1663 GLuint program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlFragCoord);
1664 EXPECT_EQ(0u, program);
1665
1666 program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlPointCoord);
1667 EXPECT_EQ(0u, program);
1668}
1669
Yuly Novikovcaa5cda2017-06-15 21:14:03 -04001670// Tests global namespace conflicts between uniforms and attributes.
1671// Based on WebGL test conformance/glsl/misc/shaders-with-name-conflicts.html.
1672TEST_P(WebGLCompatibilityTest, GlobalNamesConflict)
1673{
1674 const std::string vertexShader =
1675 "attribute vec4 foo;\n"
1676 "void main()\n"
1677 "{\n"
1678 " gl_Position = foo;\n"
1679 "}";
1680 const std::string fragmentShader =
1681 "precision mediump float;\n"
1682 "uniform vec4 foo;\n"
1683 "void main()\n"
1684 "{\n"
1685 " gl_FragColor = foo;\n"
1686 "}";
1687
1688 GLuint program = CompileProgram(vertexShader, fragmentShader);
1689 EXPECT_EQ(0u, program);
1690}
1691
Geoff Lang966c9402017-04-18 12:38:27 -04001692// Test dimension and image size validation of compressed textures
1693TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
1694{
1695 if (extensionRequestable("GL_EXT_texture_compression_dxt1"))
1696 {
1697 glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
1698 }
1699
1700 if (!extensionEnabled("GL_EXT_texture_compression_dxt1"))
1701 {
1702 std::cout << "Test skipped because GL_EXT_texture_compression_dxt1 is not available."
1703 << std::endl;
1704 return;
1705 }
1706
1707 constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
1708
1709 GLTexture texture;
1710 glBindTexture(GL_TEXTURE_2D, texture);
1711
1712 // Regular case, verify that it works
1713 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1714 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1715 ASSERT_GL_NO_ERROR();
1716
1717 // Test various dimensions that are not valid
1718 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
1719 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1720 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1721
1722 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
1723 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1724 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1725
1726 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
1727 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1728 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1729
1730 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
1731 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1732 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1733
1734 // Test various image sizes that are not valid
1735 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1736 sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
1737 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1738
1739 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1740 sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
1741 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1742
1743 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
1744 CompressedImageDXT1);
1745 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1746
1747 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
1748 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1749 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1750
1751 // Fill a full mip chain and verify that it works
1752 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1753 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1754 glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
1755 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1756 glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
1757 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1758 ASSERT_GL_NO_ERROR();
1759
1760 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1761 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1762 ASSERT_GL_NO_ERROR();
1763
1764 // Test that non-block size sub-uploads are not valid for the 0 mip
1765 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1766 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1767 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1768
1769 // Test that non-block size sub-uploads are valid for if they fill the whole mip
1770 glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1771 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1772 glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1773 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1774 ASSERT_GL_NO_ERROR();
1775
1776 // Test that if the format miss-matches the texture, an error is generated
1777 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
1778 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1779 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1780}
1781
Geoff Lang677bb6f2017-04-05 12:40:40 -04001782TEST_P(WebGLCompatibilityTest, L32FTextures)
1783{
1784 constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f};
1785 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
1786
1787 for (auto extension : FloatingPointTextureExtensions)
1788 {
1789 if (strlen(extension) > 0 && extensionRequestable(extension))
1790 {
1791 glRequestExtensionANGLE(extension);
1792 ASSERT_GL_NO_ERROR();
1793 }
1794
1795 // Unsized L 32F
1796 {
1797 bool texture = extensionEnabled("GL_OES_texture_float");
1798 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1799 bool render = false;
1800 TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
1801 textureData, readPixelData);
1802 }
1803
1804 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1805 {
1806 // Sized L 32F
1807 bool texture = extensionEnabled("GL_OES_texture_float") &&
1808 extensionEnabled("GL_EXT_texture_storage");
1809 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1810 bool render = false;
1811 TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
1812 render, textureData, readPixelData);
1813 }
1814 }
1815}
1816
1817TEST_P(WebGLCompatibilityTest, A32FTextures)
1818{
1819 constexpr float textureData[] = {33.33f, 0.0f, 0.0f, 0.0f};
1820 constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
1821
1822 for (auto extension : FloatingPointTextureExtensions)
1823 {
1824 if (strlen(extension) > 0 && extensionRequestable(extension))
1825 {
1826 glRequestExtensionANGLE(extension);
1827 ASSERT_GL_NO_ERROR();
1828 }
1829
1830 // Unsized A 32F
1831 {
1832 bool texture = extensionEnabled("GL_OES_texture_float");
1833 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1834 bool render = false;
1835 TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
1836 textureData, readPixelData);
1837 }
1838
1839 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1840 {
1841 // Sized A 32F
1842 bool texture = extensionEnabled("GL_OES_texture_float") &&
1843 extensionEnabled("GL_EXT_texture_storage");
1844 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1845 bool render = false;
1846 TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
1847 textureData, readPixelData);
1848 }
1849 }
1850}
1851
1852TEST_P(WebGLCompatibilityTest, LA32FTextures)
1853{
1854 constexpr float textureData[] = {-0.21f, 15.1f, 0.0f, 0.0f};
1855 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
1856 textureData[1]};
1857
1858 for (auto extension : FloatingPointTextureExtensions)
1859 {
1860 if (strlen(extension) > 0 && extensionRequestable(extension))
1861 {
1862 glRequestExtensionANGLE(extension);
1863 ASSERT_GL_NO_ERROR();
1864 }
1865
1866 // Unsized LA 32F
1867 {
1868 bool texture = extensionEnabled("GL_OES_texture_float");
1869 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1870 bool render = false;
1871 TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
1872 filter, render, textureData, readPixelData);
1873 }
1874
1875 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1876 {
1877 // Sized LA 32F
1878 bool texture = extensionEnabled("GL_OES_texture_float") &&
1879 extensionEnabled("GL_EXT_texture_storage");
1880 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1881 bool render = false;
1882 TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
1883 filter, render, textureData, readPixelData);
1884 }
1885 }
1886}
1887
1888TEST_P(WebGLCompatibilityTest, R32FTextures)
1889{
1890 constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
1891
1892 for (auto extension : FloatingPointTextureExtensions)
1893 {
1894 if (strlen(extension) > 0 && extensionRequestable(extension))
1895 {
1896 glRequestExtensionANGLE(extension);
1897 ASSERT_GL_NO_ERROR();
1898 }
1899
1900 // Unsized R 32F
1901 {
1902 bool texture =
1903 extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg");
1904 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1905 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1906 TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
1907 }
1908
1909 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1910 {
1911 // Sized R 32F
1912 bool texture =
1913 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1914 extensionEnabled("GL_EXT_texture_rg") &&
1915 extensionEnabled("GL_EXT_texture_storage"));
1916 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1917 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1918 TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
1919 }
1920 }
1921}
1922
1923TEST_P(WebGLCompatibilityTest, RG32FTextures)
1924{
1925 constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
1926
1927 for (auto extension : FloatingPointTextureExtensions)
1928 {
1929 if (strlen(extension) > 0 && extensionRequestable(extension))
1930 {
1931 glRequestExtensionANGLE(extension);
1932 ASSERT_GL_NO_ERROR();
1933 }
1934
1935 // Unsized RG 32F
1936 {
1937 bool texture =
1938 (extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg"));
1939 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1940 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1941 TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
1942 }
1943
1944 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1945 {
1946 // Sized RG 32F
1947 bool texture =
1948 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1949 extensionEnabled("GL_EXT_texture_rg") &&
1950 extensionEnabled("GL_EXT_texture_storage"));
1951 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1952 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1953 TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
1954 }
1955 }
1956}
1957
1958TEST_P(WebGLCompatibilityTest, RGB32FTextures)
1959{
Geoff Lang40762ef2017-05-08 13:47:03 -04001960 if (IsLinux() && IsIntel())
1961 {
1962 std::cout << "Test skipped on Linux Intel." << std::endl;
1963 return;
1964 }
1965
Geoff Lang677bb6f2017-04-05 12:40:40 -04001966 constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
1967
1968 for (auto extension : FloatingPointTextureExtensions)
1969 {
1970 if (strlen(extension) > 0 && extensionRequestable(extension))
1971 {
1972 glRequestExtensionANGLE(extension);
1973 ASSERT_GL_NO_ERROR();
1974 }
1975
1976 // Unsized RGB 32F
1977 {
1978 bool texture = extensionEnabled("GL_OES_texture_float");
1979 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1980 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
1981 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
1982 }
1983
1984 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1985 {
1986 // Sized RGBA 32F
1987 bool texture =
1988 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1989 extensionEnabled("GL_EXT_texture_storage"));
1990 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1991 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
1992 TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
1993 data);
1994 }
1995 }
1996}
1997
1998TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
1999{
2000 constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2001
2002 for (auto extension : FloatingPointTextureExtensions)
2003 {
2004 if (strlen(extension) > 0 && extensionRequestable(extension))
2005 {
2006 glRequestExtensionANGLE(extension);
2007 ASSERT_GL_NO_ERROR();
2008 }
2009
2010 // Unsized RGBA 32F
2011 {
2012 bool texture = extensionEnabled("GL_OES_texture_float");
2013 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2014 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2015 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2016 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
2017 }
2018
2019 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2020 {
2021 // Sized RGBA 32F
2022 bool texture =
2023 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
2024 extensionEnabled("GL_EXT_texture_storage"));
2025 bool filter = extensionEnabled("GL_OES_texture_float_linear");
2026 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
2027 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
2028 TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
2029 data);
2030 }
2031 }
2032}
2033
2034TEST_P(WebGLCompatibilityTest, R16FTextures)
2035{
2036 constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
2037 const GLushort textureData[] = {
2038 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2039 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2040
2041 for (auto extension : FloatingPointTextureExtensions)
2042 {
2043 if (strlen(extension) > 0 && extensionRequestable(extension))
2044 {
2045 glRequestExtensionANGLE(extension);
2046 ASSERT_GL_NO_ERROR();
2047 }
2048
2049 // Unsized R 16F (OES)
2050 {
2051 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2052 extensionEnabled("GL_EXT_texture_rg");
2053 bool filter = getClientMajorVersion() >= 3 ||
2054 extensionEnabled("GL_OES_texture_half_float_linear");
2055 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2056 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
2057 textureData, readPixelsData);
2058 }
2059
2060 // Unsized R 16F
2061 {
2062 bool texture = false;
2063 bool filter = false;
2064 bool render = false;
2065 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2066 textureData, readPixelsData);
2067 }
2068
2069 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2070 {
2071 // Sized R 16F
2072 bool texture = getClientMajorVersion() >= 3;
2073 bool filter = getClientMajorVersion() >= 3 ||
2074 extensionEnabled("GL_OES_texture_half_float_linear");
2075 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2076 extensionEnabled("GL_EXT_color_buffer_float");
2077 TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
2078 textureData, readPixelsData);
2079 }
2080 }
2081}
2082
2083TEST_P(WebGLCompatibilityTest, RG16FTextures)
2084{
2085 constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
2086 const GLushort textureData[] = {
2087 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2088 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2089
2090 for (auto extension : FloatingPointTextureExtensions)
2091 {
2092 if (strlen(extension) > 0 && extensionRequestable(extension))
2093 {
2094 glRequestExtensionANGLE(extension);
2095 ASSERT_GL_NO_ERROR();
2096 }
2097
2098 // Unsized RG 16F (OES)
2099 {
2100 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
2101 extensionEnabled("GL_EXT_texture_rg");
2102 bool filter = getClientMajorVersion() >= 3 ||
2103 extensionEnabled("GL_OES_texture_half_float_linear");
2104 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") &&
2105 extensionEnabled("GL_EXT_texture_rg");
2106 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
2107 textureData, readPixelsData);
2108 }
2109
2110 // Unsized RG 16F
2111 {
2112 bool texture = false;
2113 bool filter = false;
2114 bool render = false;
2115 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2116 textureData, readPixelsData);
2117 }
2118
2119 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2120 {
2121 // Sized RG 16F
2122 bool texture = getClientMajorVersion() >= 3;
2123 bool filter = getClientMajorVersion() >= 3 ||
2124 extensionEnabled("GL_OES_texture_half_float_linear");
2125 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2126 extensionEnabled("GL_EXT_color_buffer_float");
2127 TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
2128 textureData, readPixelsData);
2129 }
2130 }
2131}
2132
2133TEST_P(WebGLCompatibilityTest, RGB16FTextures)
2134{
Geoff Lang40762ef2017-05-08 13:47:03 -04002135 if (IsOzone() && IsIntel())
2136 {
2137 std::cout << "Test skipped on Intel Ozone." << std::endl;
2138 return;
2139 }
2140
Geoff Lang677bb6f2017-04-05 12:40:40 -04002141 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
2142 const GLushort textureData[] = {
2143 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2144 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2145
2146 for (auto extension : FloatingPointTextureExtensions)
2147 {
2148 if (strlen(extension) > 0 && extensionRequestable(extension))
2149 {
2150 glRequestExtensionANGLE(extension);
2151 ASSERT_GL_NO_ERROR();
2152 }
2153
2154 // Unsized RGB 16F (OES)
2155 {
2156 bool texture = extensionEnabled("GL_OES_texture_half_float");
2157 bool filter = getClientMajorVersion() >= 3 ||
2158 extensionEnabled("GL_OES_texture_half_float_linear");
2159 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2160 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
2161 textureData, readPixelsData);
2162 }
2163
2164 // Unsized RGB 16F
2165 {
2166 bool texture = false;
2167 bool filter = false;
2168 bool render = false;
2169 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2170 textureData, readPixelsData);
2171 }
2172
2173 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2174 {
2175 // Sized RGB 16F
2176 bool texture = getClientMajorVersion() >= 3;
2177 bool filter = getClientMajorVersion() >= 3 ||
2178 extensionEnabled("GL_OES_texture_half_float_linear");
2179 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2180 TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2181 textureData, readPixelsData);
2182 }
2183 }
2184}
2185
2186TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
2187{
Geoff Lang40762ef2017-05-08 13:47:03 -04002188 if (IsOzone() && IsIntel())
2189 {
2190 std::cout << "Test skipped on Intel Ozone." << std::endl;
2191 return;
2192 }
2193
Geoff Lang677bb6f2017-04-05 12:40:40 -04002194 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2195 const GLushort textureData[] = {
2196 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2197 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2198
2199 for (auto extension : FloatingPointTextureExtensions)
2200 {
2201 if (strlen(extension) > 0 && extensionRequestable(extension))
2202 {
2203 glRequestExtensionANGLE(extension);
2204 ASSERT_GL_NO_ERROR();
2205 }
2206
2207 // Unsized RGBA 16F (OES)
2208 {
2209 bool texture = extensionEnabled("GL_OES_texture_half_float");
2210 bool filter = getClientMajorVersion() >= 3 ||
2211 extensionEnabled("GL_OES_texture_half_float_linear");
2212 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2213 extensionEnabled("GL_EXT_color_buffer_float");
2214 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
2215 textureData, readPixelsData);
2216 }
2217
2218 // Unsized RGBA 16F
2219 {
2220 bool texture = false;
2221 bool filter = false;
2222 bool render = false;
2223 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2224 textureData, readPixelsData);
2225 }
2226
2227 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2228 {
2229 // Sized RGBA 16F
2230 bool texture = getClientMajorVersion() >= 3;
2231 bool filter = getClientMajorVersion() >= 3 ||
2232 extensionEnabled("GL_OES_texture_half_float_linear");
2233 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2234 extensionEnabled("GL_EXT_color_buffer_float");
2235 TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2236 textureData, readPixelsData);
2237 }
2238 }
2239}
2240
Geoff Lang6e898aa2017-06-02 11:17:26 -04002241// Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
2242// accepted by glTexImage2D
2243TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
2244{
2245 if (getClientMajorVersion() != 2)
2246 {
2247 std::cout << "Test skipped because it is only valid for WebGL1 contexts." << std::endl;
2248 return;
2249 }
2250
2251 if (!extensionRequestable("GL_OES_texture_float"))
2252 {
2253 std::cout << "Test skipped because GL_OES_texture_float is not requestable." << std::endl;
2254 return;
2255 }
2256 glRequestExtensionANGLE("GL_OES_texture_float");
2257 ASSERT_GL_NO_ERROR();
2258
2259 GLTexture texture;
2260 glBindTexture(GL_TEXTURE_2D, texture);
2261
2262 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2263 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2264
2265 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2266 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2267
2268 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
2269 {
2270 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
2271 ASSERT_GL_NO_ERROR();
2272
2273 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2274 EXPECT_GL_NO_ERROR();
2275 }
2276
2277 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
2278 {
2279 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
2280 ASSERT_GL_NO_ERROR();
2281
2282 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2283 EXPECT_GL_NO_ERROR();
2284 }
2285}
2286
Jamie Madill07be8bf2017-02-02 19:59:57 -05002287// This tests that rendering feedback loops works as expected with WebGL 2.
2288// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
2289TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
2290{
2291 const std::string vertexShader =
2292 "#version 300 es\n"
2293 "in vec4 aPosition;\n"
2294 "out vec2 texCoord;\n"
2295 "void main() {\n"
2296 " gl_Position = aPosition;\n"
2297 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2298 "}\n";
2299
2300 const std::string fragmentShader =
2301 "#version 300 es\n"
2302 "precision mediump float;\n"
2303 "uniform sampler2D tex;\n"
2304 "in vec2 texCoord;\n"
2305 "out vec4 oColor;\n"
2306 "void main() {\n"
2307 " oColor = texture(tex, texCoord);\n"
2308 "}\n";
2309
2310 GLsizei width = 8;
2311 GLsizei height = 8;
2312
2313 GLint maxDrawBuffers = 0;
2314 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2315 // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
2316 ASSERT_GE(maxDrawBuffers, 2);
2317
2318 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2319 glUseProgram(program.get());
2320 glViewport(0, 0, width, height);
2321
2322 GLTexture tex0;
2323 GLTexture tex1;
2324 GLFramebuffer fbo;
2325 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2326 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2327 ASSERT_GL_NO_ERROR();
2328
2329 glBindTexture(GL_TEXTURE_2D, tex1.get());
2330 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2331 ASSERT_NE(-1, texLoc);
2332 glUniform1i(texLoc, 0);
2333
2334 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2335 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2336 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2337 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
2338 ASSERT_GL_NO_ERROR();
2339
2340 drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
2341 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2342 GL_INVALID_OPERATION);
2343 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
2344}
2345
Jamie Madill1d37bc52017-02-02 19:59:58 -05002346// This test covers detection of rendering feedback loops between the FBO and a depth Texture.
2347// Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
2348TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
2349{
2350 const std::string vertexShader =
2351 "#version 300 es\n"
2352 "in vec4 aPosition;\n"
2353 "out vec2 texCoord;\n"
2354 "void main() {\n"
2355 " gl_Position = aPosition;\n"
2356 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2357 "}\n";
2358
2359 const std::string fragmentShader =
2360 "#version 300 es\n"
2361 "precision mediump float;\n"
2362 "uniform sampler2D tex;\n"
2363 "in vec2 texCoord;\n"
2364 "out vec4 oColor;\n"
2365 "void main() {\n"
2366 " oColor = texture(tex, texCoord);\n"
2367 "}\n";
2368
2369 GLsizei width = 8;
2370 GLsizei height = 8;
2371
2372 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2373 glUseProgram(program.get());
2374
2375 glViewport(0, 0, width, height);
2376
2377 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2378 glUniform1i(texLoc, 0);
2379
2380 // Create textures and allocate storage
2381 GLTexture tex0;
2382 GLTexture tex1;
2383 GLRenderbuffer rb;
2384 FillTexture2D(tex0.get(), width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2385 FillTexture2D(tex1.get(), width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
2386 GL_UNSIGNED_INT);
2387 glBindRenderbuffer(GL_RENDERBUFFER, rb.get());
2388 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
2389 ASSERT_GL_NO_ERROR();
2390
2391 GLFramebuffer fbo;
2392 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2393 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2394
2395 // Test rendering and sampling feedback loop for depth buffer
2396 glBindTexture(GL_TEXTURE_2D, tex1.get());
2397 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1.get(), 0);
2398 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2399
2400 // The same image is used as depth buffer during rendering.
2401 glEnable(GL_DEPTH_TEST);
2402 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2403 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2404
2405 // The same image is used as depth buffer. But depth mask is false.
2406 glDepthMask(GL_FALSE);
2407 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2408 EXPECT_GL_NO_ERROR();
2409
2410 // The same image is used as depth buffer. But depth test is not enabled during rendering.
2411 glDepthMask(GL_TRUE);
2412 glDisable(GL_DEPTH_TEST);
2413 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2414 EXPECT_GL_NO_ERROR();
2415
2416 // Test rendering and sampling feedback loop for stencil buffer
2417 glBindTexture(GL_RENDERBUFFER, rb.get());
2418 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
2419 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb.get());
2420 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2421 constexpr GLint stencilClearValue = 0x40;
2422 glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
2423
2424 // The same image is used as stencil buffer during rendering.
2425 glEnable(GL_STENCIL_TEST);
2426 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2427 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2428
2429 // The same image is used as stencil buffer. But stencil mask is zero.
2430 glStencilMask(0x0);
2431 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2432 EXPECT_GL_NO_ERROR();
2433
2434 // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
2435 glStencilMask(0xffff);
2436 glDisable(GL_STENCIL_TEST);
2437 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2438 EXPECT_GL_NO_ERROR();
2439}
2440
Jamie Madillfd3dd432017-02-02 19:59:59 -05002441// The source and the target for CopyTexSubImage3D are the same 3D texture.
2442// But the level of the 3D texture != the level of the read attachment.
2443TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
2444{
2445 GLTexture texture;
2446 GLFramebuffer framebuffer;
2447
2448 glBindTexture(GL_TEXTURE_3D, texture.get());
2449 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2450
2451 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2452 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2453 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
2454 ASSERT_GL_NO_ERROR();
2455
2456 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2457 EXPECT_GL_NO_ERROR();
2458}
2459
2460// The source and the target for CopyTexSubImage3D are the same 3D texture.
2461// But the zoffset of the 3D texture != the layer of the read attachment.
2462TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
2463{
2464 GLTexture texture;
2465 GLFramebuffer framebuffer;
2466
2467 glBindTexture(GL_TEXTURE_3D, texture.get());
2468 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2469
2470 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2471 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 1);
2472 ASSERT_GL_NO_ERROR();
2473
2474 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
2475 EXPECT_GL_NO_ERROR();
2476}
2477
2478// The source and the target for CopyTexSubImage3D are the same 3D texture.
2479// And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
2480TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
2481{
2482 GLTexture texture;
2483 GLFramebuffer framebuffer;
2484
2485 glBindTexture(GL_TEXTURE_3D, texture.get());
2486 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2487
2488 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2489 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2490 glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2491 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 1, 0);
2492 ASSERT_GL_NO_ERROR();
2493
2494 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2495 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2496}
2497
Corentin Wallez59c41592017-07-11 13:19:54 -04002498// Verify that errors are generated when there isn't a defined conversion between the clear type and
2499// the buffer type.
Geoff Lang76e65652017-03-27 14:58:02 -04002500TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
2501{
2502 if (IsD3D11())
2503 {
2504 std::cout << "Test skipped because it generates D3D11 runtime warnings." << std::endl;
2505 return;
2506 }
2507
2508 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
2509 constexpr int clearInt[] = {0, 0, 0, 0};
2510 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
2511
2512 GLTexture texture;
2513 GLFramebuffer framebuffer;
2514
2515 glBindTexture(GL_TEXTURE_2D, texture.get());
2516 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2517
2518 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2519 ASSERT_GL_NO_ERROR();
2520
2521 // Unsigned integer buffer
2522 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
2523 ASSERT_GL_NO_ERROR();
2524
2525 glClearBufferfv(GL_COLOR, 0, clearFloat);
2526 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2527
2528 glClearBufferiv(GL_COLOR, 0, clearInt);
2529 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2530
2531 glClearBufferuiv(GL_COLOR, 0, clearUint);
2532 EXPECT_GL_NO_ERROR();
2533
2534 glClear(GL_COLOR_BUFFER_BIT);
2535 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2536
2537 // Integer buffer
2538 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
2539 ASSERT_GL_NO_ERROR();
2540
2541 glClearBufferfv(GL_COLOR, 0, clearFloat);
2542 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2543
2544 glClearBufferiv(GL_COLOR, 0, clearInt);
2545 EXPECT_GL_NO_ERROR();
2546
2547 glClearBufferuiv(GL_COLOR, 0, clearUint);
2548 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2549
2550 glClear(GL_COLOR_BUFFER_BIT);
2551 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2552
2553 // Float buffer
Geoff Lang677bb6f2017-04-05 12:40:40 -04002554 if (extensionRequestable("GL_EXT_color_buffer_float"))
2555 {
2556 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
2557 }
Geoff Lang76e65652017-03-27 14:58:02 -04002558
Geoff Lang677bb6f2017-04-05 12:40:40 -04002559 if (extensionEnabled("GL_EXT_color_buffer_float"))
2560 {
2561 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2562 ASSERT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002563
Geoff Lang677bb6f2017-04-05 12:40:40 -04002564 glClearBufferfv(GL_COLOR, 0, clearFloat);
2565 EXPECT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002566
Geoff Lang677bb6f2017-04-05 12:40:40 -04002567 glClearBufferiv(GL_COLOR, 0, clearInt);
2568 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang76e65652017-03-27 14:58:02 -04002569
Geoff Lang677bb6f2017-04-05 12:40:40 -04002570 glClearBufferuiv(GL_COLOR, 0, clearUint);
2571 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2572
2573 glClear(GL_COLOR_BUFFER_BIT);
2574 EXPECT_GL_NO_ERROR();
2575 }
Geoff Lang76e65652017-03-27 14:58:02 -04002576
2577 // Normalized uint buffer
2578 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2579 ASSERT_GL_NO_ERROR();
2580
2581 glClearBufferfv(GL_COLOR, 0, clearFloat);
2582 EXPECT_GL_NO_ERROR();
2583
2584 glClearBufferiv(GL_COLOR, 0, clearInt);
2585 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2586
2587 glClearBufferuiv(GL_COLOR, 0, clearUint);
2588 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2589
2590 glClear(GL_COLOR_BUFFER_BIT);
2591 EXPECT_GL_NO_ERROR();
2592}
2593
Corentin Wallez59c41592017-07-11 13:19:54 -04002594// Test the interaction of WebGL compatibility clears with default framebuffers
2595TEST_P(WebGL2CompatibilityTest, ClearBufferDefaultFramebuffer)
2596{
2597 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
2598 constexpr int clearInt[] = {0, 0, 0, 0};
2599 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
2600
2601 // glClear works as usual, this is also a regression test for a bug where we
2602 // iterated on maxDrawBuffers for default framebuffers, triggering an assert
2603 glClear(GL_COLOR_BUFFER_BIT);
2604 EXPECT_GL_NO_ERROR();
2605
2606 // Default framebuffers are normalized uints, so only glClearBufferfv works.
2607 glClearBufferfv(GL_COLOR, 0, clearFloat);
2608 EXPECT_GL_NO_ERROR();
2609
2610 glClearBufferiv(GL_COLOR, 0, clearInt);
2611 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2612
2613 glClearBufferuiv(GL_COLOR, 0, clearUint);
2614 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2615}
2616
Geoff Lange4915782017-04-12 15:19:07 -04002617// Verify that errors are generate when trying to blit from an image to itself
2618TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
2619{
2620 GLTexture textures[2];
2621 glBindTexture(GL_TEXTURE_2D, textures[0]);
2622 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
2623 glBindTexture(GL_TEXTURE_2D, textures[1]);
2624 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
2625
2626 GLRenderbuffer renderbuffers[2];
2627 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
2628 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
2629 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
2630 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
2631
2632 GLFramebuffer framebuffers[2];
2633 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
2634 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
2635
2636 ASSERT_GL_NO_ERROR();
2637
2638 // Same texture
2639 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
2640 0);
2641 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
2642 0);
2643 ASSERT_GL_NO_ERROR();
2644 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2645 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2646
2647 // Same textures but different renderbuffers
2648 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2649 renderbuffers[0]);
2650 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2651 renderbuffers[1]);
2652 ASSERT_GL_NO_ERROR();
2653 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
2654 ASSERT_GL_NO_ERROR();
2655 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2656 GL_NEAREST);
2657 ASSERT_GL_NO_ERROR();
2658 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
2659 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2660 GL_NEAREST);
2661 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2662
2663 // Same renderbuffers but different textures
2664 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
2665 0);
2666 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
2667 0);
2668 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2669 renderbuffers[0]);
2670 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2671 renderbuffers[0]);
2672 ASSERT_GL_NO_ERROR();
2673 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2674 ASSERT_GL_NO_ERROR();
2675 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2676 GL_NEAREST);
2677 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2678 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
2679 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2680 GL_NEAREST);
2681 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2682}
2683
Geoff Lange0cff192017-05-30 13:04:56 -04002684// Verify that errors are generated when the fragment shader output doesn't match the bound color
2685// buffer types
2686TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
2687{
2688 const std::string vertexShader =
2689 "#version 300 es\n"
2690 "void main() {\n"
2691 " gl_Position = vec4(0, 0, 0, 1);\n"
2692 "}\n";
2693
2694 const std::string fragmentShader =
2695 "#version 300 es\n"
2696 "precision mediump float;\n"
2697 "layout(location = 0) out vec4 floatOutput;\n"
2698 "layout(location = 1) out uvec4 uintOutput;\n"
2699 "layout(location = 2) out ivec4 intOutput;\n"
2700 "void main() {\n"
2701 " floatOutput = vec4(0, 0, 0, 1);\n"
2702 " uintOutput = uvec4(0, 0, 0, 1);\n"
2703 " intOutput = ivec4(0, 0, 0, 1);\n"
2704 "}\n";
2705
2706 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2707 glUseProgram(program.get());
2708
2709 GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
2710 GLuint uintLocation = glGetFragDataLocation(program, "uintOutput");
2711 GLuint intLocation = glGetFragDataLocation(program, "intOutput");
2712
2713 GLFramebuffer fbo;
2714 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2715
2716 GLRenderbuffer floatRenderbuffer;
2717 glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
2718 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
2719 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
2720 floatRenderbuffer);
2721
2722 GLRenderbuffer uintRenderbuffer;
2723 glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
2724 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
2725 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2726 uintRenderbuffer);
2727
2728 GLRenderbuffer intRenderbuffer;
2729 glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
2730 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
2731 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2732 intRenderbuffer);
2733
2734 ASSERT_GL_NO_ERROR();
2735
2736 GLint maxDrawBuffers = 0;
2737 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2738 std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
2739 drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
2740 drawBuffers[uintLocation] = GL_COLOR_ATTACHMENT0 + uintLocation;
2741 drawBuffers[intLocation] = GL_COLOR_ATTACHMENT0 + intLocation;
2742
2743 glDrawBuffers(maxDrawBuffers, drawBuffers.data());
2744
2745 // Check that the correct case generates no errors
2746 glDrawArrays(GL_TRIANGLES, 0, 6);
2747 EXPECT_GL_NO_ERROR();
2748
2749 // Unbind some buffers and verify that there are still no errors
2750 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2751 0);
2752 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2753 0);
2754 glDrawArrays(GL_TRIANGLES, 0, 6);
2755 EXPECT_GL_NO_ERROR();
2756
2757 // Swap the int and uint buffers to and verify that an error is generated
2758 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2759 intRenderbuffer);
2760 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2761 uintRenderbuffer);
2762 glDrawArrays(GL_TRIANGLES, 0, 6);
2763 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2764
2765 // Swap the float and uint buffers to and verify that an error is generated
2766 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2767 floatRenderbuffer);
2768 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
2769 uintRenderbuffer);
2770 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2771 intRenderbuffer);
2772 glDrawArrays(GL_TRIANGLES, 0, 6);
2773 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2774}
2775
Geoff Lang9ab5b822017-05-30 16:19:23 -04002776// Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
2777// types
2778TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMissmatch)
2779{
2780 const std::string vertexShader =
2781 "#version 300 es\n"
2782 "in vec4 floatInput;\n"
2783 "in uvec4 uintInput;\n"
2784 "in ivec4 intInput;\n"
2785 "void main() {\n"
2786 " gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);\n"
2787 "}\n";
2788
2789 const std::string fragmentShader =
2790 "#version 300 es\n"
2791 "precision mediump float;\n"
2792 "out vec4 outputColor;\n"
2793 "void main() {\n"
2794 " outputColor = vec4(0, 0, 0, 1);"
2795 "}\n";
2796
2797 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2798 glUseProgram(program.get());
2799
2800 GLint floatLocation = glGetAttribLocation(program, "floatInput");
2801 GLint uintLocation = glGetAttribLocation(program, "uintInput");
2802 GLint intLocation = glGetAttribLocation(program, "intInput");
2803
2804 // Default attributes are of float types
2805 glDrawArrays(GL_TRIANGLES, 0, 6);
2806 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2807
2808 // Set the default attributes to the correct types, should succeed
2809 glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
2810 glVertexAttribI4i(intLocation, 0, 0, 0, 1);
2811 glDrawArrays(GL_TRIANGLES, 0, 6);
2812 EXPECT_GL_NO_ERROR();
2813
2814 // Change the default float attribute to an integer, should fail
2815 glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
2816 glDrawArrays(GL_TRIANGLES, 0, 6);
2817 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2818
2819 // Use a buffer for some attributes
2820 GLBuffer buffer;
2821 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2822 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
2823 glEnableVertexAttribArray(floatLocation);
2824 glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
2825 glDrawArrays(GL_TRIANGLES, 0, 6);
2826 EXPECT_GL_NO_ERROR();
2827
2828 // Use a float pointer attrib for a uint input
2829 glEnableVertexAttribArray(uintLocation);
2830 glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
2831 glDrawArrays(GL_TRIANGLES, 0, 6);
2832 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2833
2834 // Use a uint pointer for the uint input
2835 glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
2836 glDrawArrays(GL_TRIANGLES, 0, 6);
2837 EXPECT_GL_NO_ERROR();
2838}
2839
Corentin Walleze7557742017-06-01 13:09:57 -04002840// Tests the WebGL removal of undefined behavior when attachments aren't written to.
2841TEST_P(WebGLCompatibilityTest, DrawBuffers)
2842{
Corentin Walleze7557742017-06-01 13:09:57 -04002843 // Make sure we can use at least 4 attachments for the tests.
2844 bool useEXT = false;
2845 if (getClientMajorVersion() < 3)
2846 {
2847 if (!extensionRequestable("GL_EXT_draw_buffers"))
2848 {
2849 std::cout << "Test skipped because draw buffers are not available" << std::endl;
2850 return;
2851 }
2852
2853 glRequestExtensionANGLE("GL_EXT_draw_buffers");
2854 useEXT = true;
2855 EXPECT_GL_NO_ERROR();
2856 }
2857
2858 GLint maxDrawBuffers = 0;
2859 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2860 if (maxDrawBuffers < 4)
2861 {
2862 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
2863 return;
2864 }
2865
2866 // Clears all the renderbuffers to red.
2867 auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
2868 GLFramebuffer clearFBO;
2869 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, clearFBO);
2870
2871 glClearColor(1, 0, 0, 1);
2872 for (int i = 0; i < 4; ++i)
2873 {
2874 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
2875 renderbuffers[i]);
2876 glClear(GL_COLOR_BUFFER_BIT);
2877 }
2878 ASSERT_GL_NO_ERROR();
2879 };
2880
2881 // Checks that the renderbuffers specified by mask have the correct color
2882 auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
2883 GLFramebuffer readFBO;
2884 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
2885
2886 for (int i = 0; i < 4; ++i)
2887 {
2888 if (mask & (1 << i))
2889 {
2890 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2891 GL_RENDERBUFFER, renderbuffers[i]);
2892 EXPECT_PIXEL_COLOR_EQ(0, 0, color);
2893 }
2894 }
2895 ASSERT_GL_NO_ERROR();
2896 };
2897
2898 // Depending on whether we are using the extension or ES3, a different entrypoint must be called
2899 auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
2900 if (useEXT)
2901 {
2902 glDrawBuffersEXT(numBuffers, buffers);
2903 }
2904 else
2905 {
2906 glDrawBuffers(numBuffers, buffers);
2907 }
2908 };
2909
2910 // Initialized the test framebuffer
2911 GLFramebuffer drawFBO;
2912 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2913
2914 GLRenderbuffer renderbuffers[4];
2915 for (int i = 0; i < 4; ++i)
2916 {
2917 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
2918 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
2919 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
2920 renderbuffers[i]);
2921 }
2922
2923 ASSERT_GL_NO_ERROR();
2924
2925 const char *vertESSL1 =
2926 "attribute vec4 a_pos;\n"
2927 "void main()\n"
2928 "{\n"
2929 " gl_Position = a_pos;\n"
2930 "}\n";
2931 const char *vertESSL3 =
2932 "#version 300 es\n"
2933 "in vec4 a_pos;\n"
2934 "void main()\n"
2935 "{\n"
2936 " gl_Position = a_pos;\n"
2937 "}\n";
2938
2939 GLenum allDrawBuffers[] = {
2940 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
2941 };
2942
2943 GLenum halfDrawBuffers[] = {
2944 GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
2945 };
2946
2947 // Test that when using gl_FragColor, only the first attachment is written to.
2948 const char *fragESSL1 =
2949 "precision highp float;\n"
2950 "void main()\n"
2951 "{\n"
2952 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
2953 "}\n";
2954 ANGLE_GL_PROGRAM(programESSL1, vertESSL1, fragESSL1);
2955
2956 {
2957 ClearEverythingToRed(renderbuffers);
2958
2959 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2960 DrawBuffers(useEXT, 4, allDrawBuffers);
2961 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
2962 ASSERT_GL_NO_ERROR();
2963
2964 CheckColors(renderbuffers, 0b0001, GLColor::green);
2965 CheckColors(renderbuffers, 0b1110, GLColor::red);
2966 }
2967
2968 // Test that when using gl_FragColor, but the first draw buffer is 0, then no attachment is
2969 // written to.
2970 {
2971 ClearEverythingToRed(renderbuffers);
2972
2973 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2974 DrawBuffers(useEXT, 4, halfDrawBuffers);
2975 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
2976 ASSERT_GL_NO_ERROR();
2977
2978 CheckColors(renderbuffers, 0b1111, GLColor::red);
2979 }
2980
2981 // Test what happens when rendering to a subset of the outputs. There is a behavior difference
2982 // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
2983 // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
2984 // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
2985 // attachments not declared in the shader should not be written to.
2986 const char *writeOddOutputsVert;
2987 const char *writeOddOutputsFrag;
2988 GLColor unwrittenColor;
2989 if (useEXT)
2990 {
2991 // In the extension, when an attachment isn't written to, it should get 0's
2992 unwrittenColor = GLColor(0, 0, 0, 0);
2993 writeOddOutputsVert = vertESSL1;
2994 writeOddOutputsFrag =
2995 "#extension GL_EXT_draw_buffers : require\n"
2996 "precision highp float;\n"
2997 "void main()\n"
2998 "{\n"
2999 " gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3000 " gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);\n"
3001 "}\n";
3002 }
3003 else
3004 {
3005 // In ES3 if an attachment isn't declared, it shouldn't get written and should be red
3006 // because of the preceding clears.
3007 unwrittenColor = GLColor::red;
3008 writeOddOutputsVert = vertESSL3;
3009 writeOddOutputsFrag =
3010 "#version 300 es\n"
3011 "precision highp float;\n"
3012 "layout(location = 1) out vec4 output1;"
3013 "layout(location = 3) out vec4 output2;"
3014 "void main()\n"
3015 "{\n"
3016 " output1 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3017 " output2 = vec4(0.0, 1.0, 0.0, 1.0);\n"
3018 "}\n";
3019 }
3020 ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
3021
3022 // Test that attachments not written to get the "unwritten" color
3023 {
3024 ClearEverythingToRed(renderbuffers);
3025
3026 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3027 DrawBuffers(useEXT, 4, allDrawBuffers);
3028 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3029 ASSERT_GL_NO_ERROR();
3030
3031 CheckColors(renderbuffers, 0b1010, GLColor::green);
3032 CheckColors(renderbuffers, 0b0101, unwrittenColor);
3033 }
3034
3035 // Test that attachments not written to get the "unwritten" color but that even when the
3036 // extension is used, disabled attachments are not written at all and stay red.
3037 {
3038 ClearEverythingToRed(renderbuffers);
3039
3040 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
3041 DrawBuffers(useEXT, 4, halfDrawBuffers);
3042 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
3043 ASSERT_GL_NO_ERROR();
3044
3045 CheckColors(renderbuffers, 0b1000, GLColor::green);
3046 CheckColors(renderbuffers, 0b0100, unwrittenColor);
3047 CheckColors(renderbuffers, 0b0011, GLColor::red);
3048 }
3049}
3050
Frank Henigmanfccbac22017-05-28 17:29:26 -04003051// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
3052// qualifiers.
3053TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
3054{
3055 const std::string vertexShader =
3056 "#version 300 es\n"
3057 "uniform Block { mediump vec4 val; };\n"
3058 "void main() { gl_Position = val; }\n";
3059 const std::string fragmentShader =
3060 "#version 300 es\n"
3061 "uniform Block { highp vec4 val; };\n"
3062 "out highp vec4 out_FragColor;\n"
3063 "void main() { out_FragColor = val; }\n";
3064
3065 GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
3066 ASSERT_NE(0u, vs);
3067 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
3068 ASSERT_NE(0u, fs);
3069
3070 GLuint program = glCreateProgram();
3071
3072 glAttachShader(program, vs);
3073 glDeleteShader(vs);
3074 glAttachShader(program, fs);
3075 glDeleteShader(fs);
3076
3077 glLinkProgram(program);
3078 GLint linkStatus;
3079 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
3080 ASSERT_EQ(0, linkStatus);
3081
3082 glDeleteProgram(program);
3083}
3084
Geoff Lang69df2422017-07-05 12:42:31 -04003085// Test no attribute vertex shaders
3086TEST_P(WebGL2CompatibilityTest, NoAttributeVertexShader)
3087{
3088 const std::string vertexShader =
3089 "#version 300 es\n"
3090 "void main()\n"
3091 "{\n"
3092 "\n"
3093 " ivec2 xy = ivec2(gl_VertexID % 2, (gl_VertexID / 2 + gl_VertexID / 3) % 2);\n"
3094 " gl_Position = vec4(vec2(xy) * 2. - 1., 0, 1);\n"
3095 "}";
3096 const std::string fragmentShader =
3097 "#version 300 es\n"
3098 "precision mediump float;\n"
3099 "out vec4 result;\n"
3100 "void main()\n"
3101 "{\n"
3102 " result = vec4(0, 1, 0, 1);\n"
3103 "}";
3104
3105 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
3106 glUseProgram(program);
3107
3108 glDrawArrays(GL_TRIANGLES, 0, 6);
3109 ASSERT_GL_NO_ERROR();
3110 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3111}
3112
Brandon Jonesed5b46f2017-07-21 08:39:17 -07003113// Tests bindAttribLocations for length limit
3114TEST_P(WebGL2CompatibilityTest, BindAttribLocationLimitation)
3115{
3116 constexpr int maxLocStringLength = 1024;
3117 const std::string tooLongString(maxLocStringLength + 1, '_');
3118
3119 glBindAttribLocation(0, 0, static_cast<const GLchar *>(tooLongString.c_str()));
3120
3121 EXPECT_GL_ERROR(GL_INVALID_VALUE);
3122}
3123
Geoff Langc287ea62016-09-16 14:46:51 -04003124// Use this to select which configurations (e.g. which renderer, which GLES major version) these
3125// tests should be run against.
3126ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
3127 ES2_D3D9(),
3128 ES2_D3D11(),
3129 ES3_D3D11(),
Geoff Langc287ea62016-09-16 14:46:51 -04003130 ES2_OPENGL(),
3131 ES3_OPENGL(),
3132 ES2_OPENGLES(),
3133 ES3_OPENGLES());
3134
Jamie Madill07be8bf2017-02-02 19:59:57 -05003135ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Geoff Langc287ea62016-09-16 14:46:51 -04003136} // namespace