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