Fix MacCatalyst build.
[WebKit-https.git] / Source / ThirdParty / ANGLE / src / libANGLE / validationEGL.cpp
1 //
2 // Copyright 2016 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 // validationEGL.cpp: Validation functions for generic EGL entry point parameters
8
9 #include "libANGLE/validationEGL.h"
10
11 #include "common/utilities.h"
12 #include "libANGLE/Config.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Device.h"
15 #include "libANGLE/Display.h"
16 #include "libANGLE/EGLSync.h"
17 #include "libANGLE/Image.h"
18 #include "libANGLE/Stream.h"
19 #include "libANGLE/Surface.h"
20 #include "libANGLE/Texture.h"
21 #include "libANGLE/Thread.h"
22 #include "libANGLE/formatutils.h"
23
24 #include <EGL/eglext.h>
25
26 namespace egl
27 {
28 namespace
29 {
30 size_t GetMaximumMipLevel(const gl::Context *context, gl::TextureType type)
31 {
32     const gl::Caps &caps = context->getCaps();
33
34     int maxDimension = 0;
35     switch (type)
36     {
37         case gl::TextureType::_2D:
38         case gl::TextureType::_2DArray:
39         case gl::TextureType::_2DMultisample:
40             maxDimension = caps.max2DTextureSize;
41             break;
42         case gl::TextureType::Rectangle:
43             maxDimension = caps.maxRectangleTextureSize;
44             break;
45         case gl::TextureType::CubeMap:
46             maxDimension = caps.maxCubeMapTextureSize;
47             break;
48         case gl::TextureType::_3D:
49             maxDimension = caps.max3DTextureSize;
50             break;
51
52         default:
53             UNREACHABLE();
54     }
55
56     return gl::log2(maxDimension);
57 }
58
59 bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::Texture *texture)
60 {
61     size_t maxMip = GetMaximumMipLevel(context, texture->getType());
62     for (size_t level = 1; level < maxMip; level++)
63     {
64         if (texture->getType() == gl::TextureType::CubeMap)
65         {
66             for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
67             {
68                 if (texture->getFormat(face, level).valid())
69                 {
70                     return true;
71                 }
72             }
73         }
74         else
75         {
76             if (texture->getFormat(gl::NonCubeTextureTypeToTarget(texture->getType()), level)
77                     .valid())
78             {
79                 return true;
80             }
81         }
82     }
83
84     return false;
85 }
86
87 bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture)
88 {
89     ASSERT(texture->getType() == gl::TextureType::CubeMap);
90     for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
91     {
92         if (!texture->getFormat(face, 0).valid())
93         {
94             return true;
95         }
96     }
97
98     return false;
99 }
100
101 Error ValidateStreamAttribute(const EGLAttrib attribute,
102                               const EGLAttrib value,
103                               const DisplayExtensions &extensions)
104 {
105     switch (attribute)
106     {
107         case EGL_STREAM_STATE_KHR:
108         case EGL_PRODUCER_FRAME_KHR:
109         case EGL_CONSUMER_FRAME_KHR:
110             return EglBadAccess() << "Attempt to initialize readonly parameter";
111         case EGL_CONSUMER_LATENCY_USEC_KHR:
112             // Technically not in spec but a latency < 0 makes no sense so we check it
113             if (value < 0)
114             {
115                 return EglBadParameter() << "Latency must be positive";
116             }
117             break;
118         case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR:
119             if (!extensions.streamConsumerGLTexture)
120             {
121                 return EglBadAttribute() << "Consumer GL extension not enabled";
122             }
123             // Again not in spec but it should be positive anyways
124             if (value < 0)
125             {
126                 return EglBadParameter() << "Timeout must be positive";
127             }
128             break;
129         default:
130             return EglBadAttribute() << "Invalid stream attribute";
131     }
132     return NoError();
133 }
134
135 Error ValidateCreateImageMipLevelCommon(gl::Context *context,
136                                         const gl::Texture *texture,
137                                         EGLAttrib level)
138 {
139     // Note that the spec EGL_create_image spec does not explicitly specify an error
140     // when the level is outside the base/max level range, but it does mention that the
141     // level "must be a part of the complete texture object <buffer>". It can be argued
142     // that out-of-range levels are not a part of the complete texture.
143     const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
144     if (level > 0 &&
145         (!texture->isMipmapComplete() || static_cast<GLuint>(level) < effectiveBaseLevel ||
146          static_cast<GLuint>(level) > texture->getTextureState().getMipmapMaxLevel()))
147     {
148         return EglBadParameter() << "texture must be complete if level is non-zero.";
149     }
150
151     if (level == 0 && !texture->isMipmapComplete() &&
152         TextureHasNonZeroMipLevelsSpecified(context, texture))
153     {
154         return EglBadParameter() << "if level is zero and the texture is incomplete, it must "
155                                     "have no mip levels specified except zero.";
156     }
157
158     return NoError();
159 }
160
161 Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute)
162 {
163     switch (attribute)
164     {
165         case EGL_BUFFER_SIZE:
166         case EGL_ALPHA_SIZE:
167         case EGL_BLUE_SIZE:
168         case EGL_GREEN_SIZE:
169         case EGL_RED_SIZE:
170         case EGL_DEPTH_SIZE:
171         case EGL_STENCIL_SIZE:
172         case EGL_CONFIG_CAVEAT:
173         case EGL_CONFIG_ID:
174         case EGL_LEVEL:
175         case EGL_NATIVE_RENDERABLE:
176         case EGL_NATIVE_VISUAL_ID:
177         case EGL_NATIVE_VISUAL_TYPE:
178         case EGL_SAMPLES:
179         case EGL_SAMPLE_BUFFERS:
180         case EGL_SURFACE_TYPE:
181         case EGL_TRANSPARENT_TYPE:
182         case EGL_TRANSPARENT_BLUE_VALUE:
183         case EGL_TRANSPARENT_GREEN_VALUE:
184         case EGL_TRANSPARENT_RED_VALUE:
185         case EGL_BIND_TO_TEXTURE_RGB:
186         case EGL_BIND_TO_TEXTURE_RGBA:
187         case EGL_MIN_SWAP_INTERVAL:
188         case EGL_MAX_SWAP_INTERVAL:
189         case EGL_LUMINANCE_SIZE:
190         case EGL_ALPHA_MASK_SIZE:
191         case EGL_COLOR_BUFFER_TYPE:
192         case EGL_RENDERABLE_TYPE:
193         case EGL_MATCH_NATIVE_PIXMAP:
194         case EGL_CONFORMANT:
195         case EGL_MAX_PBUFFER_WIDTH:
196         case EGL_MAX_PBUFFER_HEIGHT:
197         case EGL_MAX_PBUFFER_PIXELS:
198             break;
199
200         case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
201             if (!display->getExtensions().surfaceOrientation)
202             {
203                 return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled.";
204             }
205             break;
206
207         case EGL_COLOR_COMPONENT_TYPE_EXT:
208             if (!display->getExtensions().pixelFormatFloat)
209             {
210                 return EglBadAttribute() << "EGL_EXT_pixel_format_float is not enabled.";
211             }
212             break;
213
214         case EGL_RECORDABLE_ANDROID:
215             if (!display->getExtensions().recordable)
216             {
217                 return EglBadAttribute() << "EGL_ANDROID_recordable is not enabled.";
218             }
219             break;
220
221         case EGL_FRAMEBUFFER_TARGET_ANDROID:
222             if (!display->getExtensions().framebufferTargetANDROID)
223             {
224                 return EglBadAttribute() << "EGL_ANDROID_framebuffer_target is not enabled.";
225             }
226             break;
227
228         default:
229             return EglBadAttribute() << "Unknown attribute.";
230     }
231
232     return NoError();
233 }
234
235 Error ValidateConfigAttributeValue(const Display *display, EGLAttrib attribute, EGLAttrib value)
236 {
237     switch (attribute)
238     {
239
240         case EGL_BIND_TO_TEXTURE_RGB:
241         case EGL_BIND_TO_TEXTURE_RGBA:
242             switch (value)
243             {
244                 case EGL_DONT_CARE:
245                 case EGL_TRUE:
246                 case EGL_FALSE:
247                     break;
248                 default:
249                     return EglBadAttribute() << "EGL_bind_to_texture invalid attribute: " << value;
250             }
251             break;
252
253         case EGL_COLOR_BUFFER_TYPE:
254             switch (value)
255             {
256                 case EGL_RGB_BUFFER:
257                 case EGL_LUMINANCE_BUFFER:
258                 // EGL_DONT_CARE doesn't match the spec, but does match dEQP usage
259                 case EGL_DONT_CARE:
260                     break;
261                 default:
262                     return EglBadAttribute()
263                            << "EGL_color_buffer_type invalid attribute: " << value;
264             }
265             break;
266
267         case EGL_NATIVE_RENDERABLE:
268             switch (value)
269             {
270                 case EGL_DONT_CARE:
271                 case EGL_TRUE:
272                 case EGL_FALSE:
273                     break;
274                 default:
275                     return EglBadAttribute()
276                            << "EGL_native_renderable invalid attribute: " << value;
277             }
278             break;
279
280         case EGL_TRANSPARENT_TYPE:
281             switch (value)
282             {
283                 case EGL_NONE:
284                 case EGL_TRANSPARENT_RGB:
285                 // EGL_DONT_CARE doesn't match the spec, but does match dEQP usage
286                 case EGL_DONT_CARE:
287                     break;
288                 default:
289                     return EglBadAttribute() << "EGL_transparent_type invalid attribute: " << value;
290             }
291             break;
292
293         case EGL_RECORDABLE_ANDROID:
294             switch (value)
295             {
296                 case EGL_TRUE:
297                 case EGL_FALSE:
298                 case EGL_DONT_CARE:
299                     break;
300                 default:
301                     return EglBadAttribute()
302                            << "EGL_RECORDABLE_ANDROID invalid attribute: " << value;
303             }
304             break;
305
306         case EGL_COLOR_COMPONENT_TYPE_EXT:
307             switch (value)
308             {
309                 case EGL_COLOR_COMPONENT_TYPE_FIXED_EXT:
310                 case EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT:
311                 case EGL_DONT_CARE:
312                     break;
313                 default:
314                     return EglBadAttribute()
315                            << "EGL_COLOR_COMPONENT_TYPE_EXT invalid attribute: " << value;
316             }
317             break;
318
319         default:
320             break;
321     }
322
323     return NoError();
324 }
325
326 Error ValidateConfigAttributes(const Display *display, const AttributeMap &attributes)
327 {
328     for (const auto &attrib : attributes)
329     {
330         ANGLE_TRY(ValidateConfigAttribute(display, attrib.first));
331         ANGLE_TRY(ValidateConfigAttributeValue(display, attrib.first, attrib.second));
332     }
333
334     return NoError();
335 }
336
337 Error ValidateColorspaceAttribute(const DisplayExtensions &displayExtensions, EGLAttrib colorSpace)
338 {
339     switch (colorSpace)
340     {
341         case EGL_GL_COLORSPACE_SRGB:
342             break;
343         case EGL_GL_COLORSPACE_LINEAR:
344             break;
345         case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
346             if (!displayExtensions.glColorspaceDisplayP3Linear)
347             {
348                 return EglBadAttribute() << "EXT_gl_colorspace_display_p3_linear is not available.";
349             }
350             break;
351         case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
352             if (!displayExtensions.glColorspaceDisplayP3)
353             {
354                 return EglBadAttribute() << "EXT_gl_colorspace_display_p3 is not available.";
355             }
356             break;
357         case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
358             if (!displayExtensions.glColorspaceDisplayP3Passthrough)
359             {
360                 return EglBadAttribute()
361                        << "EGL_EXT_gl_colorspace_display_p3_passthrough is not available.";
362             }
363             break;
364         case EGL_GL_COLORSPACE_SCRGB_EXT:
365             if (!displayExtensions.glColorspaceScrgb)
366             {
367                 return EglBadAttribute() << "EXT_gl_colorspace_scrgb is not available.";
368             }
369             break;
370         case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
371             if (!displayExtensions.glColorspaceScrgbLinear)
372             {
373                 return EglBadAttribute() << "EXT_gl_colorspace_scrgb_linear is not available.";
374             }
375             break;
376         default:
377             return EglBadAttribute();
378     }
379     return NoError();
380 }
381 Error ValidatePlatformType(const ClientExtensions &clientExtensions, EGLAttrib platformType)
382 {
383     switch (platformType)
384     {
385         case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
386             break;
387
388         case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
389         case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
390             if (!clientExtensions.platformANGLED3D)
391             {
392                 return EglBadAttribute() << "Direct3D platform is unsupported.";
393             }
394             break;
395
396         case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
397         case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
398             if (!clientExtensions.platformANGLEOpenGL)
399             {
400                 return EglBadAttribute() << "OpenGL platform is unsupported.";
401             }
402             break;
403
404         case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
405             if (!clientExtensions.platformANGLENULL)
406             {
407                 return EglBadAttribute() << "Display type EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE "
408                                             "requires EGL_ANGLE_platform_angle_null.";
409             }
410             break;
411
412         case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
413             if (!clientExtensions.platformANGLEVulkan)
414             {
415                 return EglBadAttribute() << "Vulkan platform is unsupported.";
416             }
417             break;
418
419         case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
420             if (!clientExtensions.platformANGLEMetal)
421             {
422                 return EglBadAttribute() << "Metal platform is unsupported.";
423             }
424             break;
425
426         default:
427             return EglBadAttribute() << "Unknown platform type.";
428     }
429
430     return NoError();
431 }
432
433 Error ValidateGetPlatformDisplayCommon(EGLenum platform,
434                                        void *native_display,
435                                        const AttributeMap &attribMap)
436 {
437     const ClientExtensions &clientExtensions = Display::GetClientExtensions();
438
439     switch (platform)
440     {
441         case EGL_PLATFORM_ANGLE_ANGLE:
442             if (!clientExtensions.platformANGLE)
443             {
444                 return EglBadParameter() << "Platform ANGLE extension is not active";
445             }
446             break;
447         case EGL_PLATFORM_DEVICE_EXT:
448             if (!clientExtensions.platformDevice)
449             {
450                 return EglBadParameter() << "Platform Device extension is not active";
451             }
452             break;
453         default:
454             return EglBadConfig() << "Bad platform type.";
455     }
456
457     if (platform == EGL_PLATFORM_ANGLE_ANGLE)
458     {
459         EGLAttrib platformType       = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
460         bool enableAutoTrimSpecified = false;
461         bool enableD3D11on12         = false;
462         bool presentPathSpecified    = false;
463
464         Optional<EGLAttrib> majorVersion;
465         Optional<EGLAttrib> minorVersion;
466         Optional<EGLAttrib> deviceType;
467         Optional<EGLAttrib> eglHandle;
468
469         for (const auto &curAttrib : attribMap)
470         {
471             const EGLAttrib value = curAttrib.second;
472
473             switch (curAttrib.first)
474             {
475                 case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
476                 {
477                     ANGLE_TRY(ValidatePlatformType(clientExtensions, value));
478                     platformType = value;
479                     break;
480                 }
481
482                 case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
483                     if (value != EGL_DONT_CARE)
484                     {
485                         majorVersion = value;
486                     }
487                     break;
488
489                 case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
490                     if (value != EGL_DONT_CARE)
491                     {
492                         minorVersion = value;
493                     }
494                     break;
495
496                 case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
497                     switch (value)
498                     {
499                         case EGL_TRUE:
500                         case EGL_FALSE:
501                             break;
502                         default:
503                             return EglBadAttribute() << "Invalid automatic trim attribute";
504                     }
505                     enableAutoTrimSpecified = true;
506                     break;
507
508                 case EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE:
509                     if (!clientExtensions.platformANGLED3D ||
510                         !clientExtensions.platformANGLED3D11ON12)
511                     {
512                         return EglBadAttribute()
513                                << "EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE extension not active.";
514                     }
515
516                     switch (value)
517                     {
518                         case EGL_TRUE:
519                         case EGL_FALSE:
520                             break;
521                         default:
522                             return EglBadAttribute() << "Invalid D3D11on12 attribute";
523                     }
524                     enableD3D11on12 = true;
525                     break;
526
527                 case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE:
528                     if (!clientExtensions.experimentalPresentPath)
529                     {
530                         return EglBadAttribute()
531                                << "EGL_ANGLE_experimental_present_path extension not active";
532                     }
533
534                     switch (value)
535                     {
536                         case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE:
537                         case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE:
538                             break;
539                         default:
540                             return EglBadAttribute()
541                                    << "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE";
542                     }
543                     presentPathSpecified = true;
544                     break;
545
546                 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
547                     switch (value)
548                     {
549                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
550                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
551                             break;
552
553                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE:
554                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE:
555                             if (!clientExtensions.platformANGLED3D)
556                             {
557                                 return EglBadAttribute()
558                                        << "EGL_ANGLE_platform_angle_d3d is not supported";
559                             }
560                             break;
561
562                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE:
563                             if (!clientExtensions.platformANGLEDeviceTypeSwiftShader)
564                             {
565                                 return EglBadAttribute() << "EGL_ANGLE_platform_angle_device_type_"
566                                                             "swiftshader is not supported";
567                             }
568                             break;
569
570                         default:
571                             return EglBadAttribute() << "Invalid value for "
572                                                         "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE "
573                                                         "attrib";
574                     }
575                     deviceType = value;
576                     break;
577
578                 case EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE:
579                     if (!clientExtensions.platformANGLE)
580                     {
581                         return EglBadAttribute() << "EGL_ANGLE_platform_angle extension not active";
582                     }
583                     if (value != EGL_TRUE && value != EGL_FALSE && value != EGL_DONT_CARE)
584                     {
585                         return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE "
586                                                     "must be EGL_TRUE, EGL_FALSE, or "
587                                                     "EGL_DONT_CARE.";
588                     }
589                     break;
590
591                 case EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE:
592                     if (value != EGL_DONT_CARE)
593                     {
594                         eglHandle = value;
595                     }
596                     break;
597
598                 case EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE:
599                     if (!clientExtensions.platformANGLEContextVirtualization)
600                     {
601                         return EglBadAttribute() << "EGL_ANGLE_platform_angle_context_"
602                                                     "virtualization extension not active";
603                     }
604
605                     switch (value)
606                     {
607                         case EGL_DONT_CARE:
608                         case EGL_FALSE:
609                         case EGL_TRUE:
610                             break;
611
612                         default:
613                             return EglBadAttribute() << "Invalid value for "
614                                                         "EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_"
615                                                         "ANGLE attrib";
616                     }
617                     break;
618
619                 default:
620                     break;
621             }
622         }
623
624         if (!majorVersion.valid() && minorVersion.valid())
625         {
626             return EglBadAttribute()
627                    << "Must specify major version if you specify a minor version.";
628         }
629
630         if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
631             platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
632         {
633             return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a "
634                                         "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
635         }
636
637         if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
638         {
639             return EglBadAttribute() << "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE "
640                                         "requires a device type of "
641                                         "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
642         }
643
644         if (enableD3D11on12)
645         {
646             if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
647             {
648                 return EglBadAttribute() << "EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE "
649                                             "requires a platform type of "
650                                             "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
651             }
652
653             if (deviceType.valid() && deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE &&
654                 deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
655             {
656                 return EglBadAttribute() << "EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE requires a device "
657                                             "type of EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE "
658                                             "or EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE";
659             }
660         }
661
662         if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
663         {
664             return EglBadAttribute() << "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a "
665                                         "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
666         }
667
668         if (deviceType.valid())
669         {
670             switch (deviceType.value())
671             {
672                 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE:
673                 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE:
674                     if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
675                         platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
676                     {
677                         return EglBadAttribute()
678                                << "This device type requires a "
679                                   "platform type of EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or "
680                                   "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE.";
681                     }
682                     break;
683
684                 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE:
685                     if (platformType != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
686                     {
687                         return EglBadAttribute()
688                                << "This device type requires a "
689                                   "platform type of EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE.";
690                     }
691                     break;
692
693                 default:
694                     break;
695             }
696         }
697
698         if (platformType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
699         {
700             if ((majorVersion.valid() && majorVersion.value() != 1) ||
701                 (minorVersion.valid() && minorVersion.value() != 0))
702             {
703                 return EglBadAttribute() << "EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE currently "
704                                             "only supports Vulkan 1.0.";
705             }
706         }
707
708         if (eglHandle.valid() && platformType != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE &&
709             platformType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
710         {
711             return EglBadAttribute() << "EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE requires a "
712                                         "device type of EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE.";
713         }
714     }
715     else if (platform == EGL_PLATFORM_DEVICE_EXT)
716     {
717         Device *eglDevice = static_cast<Device *>(native_display);
718         if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice))
719         {
720             return EglBadAttribute() << "native_display should be a valid EGL device if "
721                                         "platform equals EGL_PLATFORM_DEVICE_EXT";
722         }
723     }
724     else
725     {
726         UNREACHABLE();
727     }
728
729     if (attribMap.contains(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE))
730     {
731         if (!clientExtensions.featureControlANGLE)
732         {
733             return EglBadAttribute() << "EGL_ANGLE_feature_control is not supported";
734         }
735         else if (attribMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0) == 0)
736         {
737             return EglBadAttribute()
738                    << "EGL_FEATURE_OVERRIDES_ENABLED_ANGLE must be a valid pointer";
739         }
740     }
741     if (attribMap.contains(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE))
742     {
743         if (!clientExtensions.featureControlANGLE)
744         {
745             return EglBadAttribute() << "EGL_ANGLE_feature_control is not supported";
746         }
747         else if (attribMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0) == 0)
748         {
749             return EglBadAttribute()
750                    << "EGL_FEATURE_OVERRIDES_DISABLED_ANGLE must be a valid pointer";
751         }
752     }
753
754     return NoError();
755 }
756
757 Error ValidateStream(const Display *display, const Stream *stream)
758 {
759     ANGLE_TRY(ValidateDisplay(display));
760
761     const DisplayExtensions &displayExtensions = display->getExtensions();
762     if (!displayExtensions.stream)
763     {
764         return EglBadAccess() << "Stream extension not active";
765     }
766
767     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
768     {
769         return EglBadStream() << "Invalid stream";
770     }
771
772     return NoError();
773 }
774
775 Error ValidateLabeledObject(Thread *thread,
776                             const Display *display,
777                             ObjectType objectType,
778                             EGLObjectKHR object,
779                             LabeledObject **outLabeledObject)
780 {
781     switch (objectType)
782     {
783         case ObjectType::Context:
784         {
785             gl::Context *context = static_cast<gl::Context *>(object);
786             ANGLE_TRY(ValidateContext(display, context));
787             *outLabeledObject = context;
788             break;
789         }
790
791         case ObjectType::Display:
792         {
793             ANGLE_TRY(ValidateDisplay(display));
794             if (display != object)
795             {
796                 return EglBadParameter() << "when object type is EGL_OBJECT_DISPLAY_KHR, the "
797                                             "object must be the same as the display.";
798             }
799
800             *outLabeledObject = static_cast<Display *>(object);
801             break;
802         }
803
804         case ObjectType::Image:
805         {
806             Image *image = static_cast<Image *>(object);
807             ANGLE_TRY(ValidateImage(display, image));
808             *outLabeledObject = image;
809             break;
810         }
811
812         case ObjectType::Stream:
813         {
814             Stream *stream = static_cast<Stream *>(object);
815             ANGLE_TRY(ValidateStream(display, stream));
816             *outLabeledObject = stream;
817             break;
818         }
819
820         case ObjectType::Surface:
821         {
822             Surface *surface = static_cast<Surface *>(object);
823             ANGLE_TRY(ValidateSurface(display, surface));
824             *outLabeledObject = surface;
825             break;
826         }
827
828         case ObjectType::Sync:
829         {
830             Sync *sync = static_cast<Sync *>(object);
831             ANGLE_TRY(ValidateSync(display, sync));
832             *outLabeledObject = sync;
833             break;
834         }
835
836         case ObjectType::Thread:
837         {
838             *outLabeledObject = thread;
839             break;
840         }
841
842         default:
843             return EglBadParameter() << "unknown object type.";
844     }
845
846     return NoError();
847 }
848
849 // This is a common sub-check of Display status that's shared by multiple functions
850 Error ValidateDisplayPointer(const Display *display)
851 {
852     if (display == EGL_NO_DISPLAY)
853     {
854         return EglBadDisplay() << "display is EGL_NO_DISPLAY.";
855     }
856
857     if (!Display::isValidDisplay(display))
858     {
859         return EglBadDisplay() << "display is not a valid display.";
860     }
861
862     return NoError();
863 }
864
865 bool ValidCompositorTimingName(CompositorTiming name)
866 {
867     switch (name)
868     {
869         case CompositorTiming::CompositeDeadline:
870         case CompositorTiming::CompositInterval:
871         case CompositorTiming::CompositToPresentLatency:
872             return true;
873
874         default:
875             return false;
876     }
877 }
878
879 bool ValidTimestampType(Timestamp timestamp)
880 {
881     switch (timestamp)
882     {
883         case Timestamp::RequestedPresentTime:
884         case Timestamp::RenderingCompleteTime:
885         case Timestamp::CompositionLatchTime:
886         case Timestamp::FirstCompositionStartTime:
887         case Timestamp::LastCompositionStartTime:
888         case Timestamp::FirstCompositionGPUFinishedTime:
889         case Timestamp::DisplayPresentTime:
890         case Timestamp::DequeueReadyTime:
891         case Timestamp::ReadsDoneTime:
892             return true;
893
894         default:
895             return false;
896     }
897 }
898
899 }  // anonymous namespace
900
901 Error ValidateDisplay(const Display *display)
902 {
903     ANGLE_TRY(ValidateDisplayPointer(display));
904
905     if (!display->isInitialized())
906     {
907         return EglNotInitialized() << "display is not initialized.";
908     }
909
910     if (display->isDeviceLost())
911     {
912         return EglContextLost() << "display had a context loss";
913     }
914
915     return NoError();
916 }
917
918 Error ValidateSurface(const Display *display, const Surface *surface)
919 {
920     ANGLE_TRY(ValidateDisplay(display));
921
922     if (!display->isValidSurface(surface))
923     {
924         return EglBadSurface();
925     }
926
927     return NoError();
928 }
929
930 Error ValidateConfig(const Display *display, const Config *config)
931 {
932     ANGLE_TRY(ValidateDisplay(display));
933
934     if (!display->isValidConfig(config))
935     {
936         return EglBadConfig();
937     }
938
939     return NoError();
940 }
941
942 Error ValidateContext(const Display *display, const gl::Context *context)
943 {
944     ANGLE_TRY(ValidateDisplay(display));
945
946     if (!display->isValidContext(context))
947     {
948         return EglBadContext();
949     }
950
951     return NoError();
952 }
953
954 Error ValidateImage(const Display *display, const Image *image)
955 {
956     ANGLE_TRY(ValidateDisplay(display));
957
958     if (!display->isValidImage(image))
959     {
960         return EglBadParameter() << "image is not valid.";
961     }
962
963     return NoError();
964 }
965
966 Error ValidateDevice(const Device *device)
967 {
968     if (device == EGL_NO_DEVICE_EXT)
969     {
970         return EglBadAccess() << "device is EGL_NO_DEVICE.";
971     }
972
973     if (!Device::IsValidDevice(device))
974     {
975         return EglBadAccess() << "device is not valid.";
976     }
977
978     return NoError();
979 }
980
981 Error ValidateSync(const Display *display, const Sync *sync)
982 {
983     ANGLE_TRY(ValidateDisplay(display));
984
985     if (!display->isValidSync(sync))
986     {
987         return EglBadParameter() << "sync object is not valid.";
988     }
989
990     return NoError();
991 }
992
993 const Thread *GetThreadIfValid(const Thread *thread)
994 {
995     // Threads should always be valid
996     return thread;
997 }
998
999 const Display *GetDisplayIfValid(const Display *display)
1000 {
1001     if (ValidateDisplay(display).isError())
1002     {
1003         return nullptr;
1004     }
1005
1006     return display;
1007 }
1008
1009 const Surface *GetSurfaceIfValid(const Display *display, const Surface *surface)
1010 {
1011     if (ValidateSurface(display, surface).isError())
1012     {
1013         return nullptr;
1014     }
1015
1016     return surface;
1017 }
1018
1019 const Image *GetImageIfValid(const Display *display, const Image *image)
1020 {
1021     if (ValidateImage(display, image).isError())
1022     {
1023         return nullptr;
1024     }
1025
1026     return image;
1027 }
1028
1029 const Stream *GetStreamIfValid(const Display *display, const Stream *stream)
1030 {
1031     if (ValidateStream(display, stream).isError())
1032     {
1033         return nullptr;
1034     }
1035
1036     return stream;
1037 }
1038
1039 const gl::Context *GetContextIfValid(const Display *display, const gl::Context *context)
1040 {
1041     if (ValidateContext(display, context).isError())
1042     {
1043         return nullptr;
1044     }
1045
1046     return context;
1047 }
1048
1049 const Device *GetDeviceIfValid(const Device *device)
1050 {
1051     if (ValidateDevice(device).isError())
1052     {
1053         return nullptr;
1054     }
1055
1056     return device;
1057 }
1058
1059 const Sync *GetSyncIfValid(const Display *display, const Sync *sync)
1060 {
1061     if (ValidateSync(display, sync).isError())
1062     {
1063         return nullptr;
1064     }
1065
1066     return sync;
1067 }
1068
1069 LabeledObject *GetLabeledObjectIfValid(Thread *thread,
1070                                        const Display *display,
1071                                        ObjectType objectType,
1072                                        EGLObjectKHR object)
1073 {
1074     LabeledObject *labeledObject = nullptr;
1075     if (ValidateLabeledObject(thread, display, objectType, object, &labeledObject).isError())
1076     {
1077         return nullptr;
1078     }
1079
1080     return labeledObject;
1081 }
1082
1083 Error ValidateInitialize(const Display *display)
1084 {
1085     return ValidateDisplayPointer(display);
1086 }
1087
1088 Error ValidateTerminate(const Display *display)
1089 {
1090     return ValidateDisplayPointer(display);
1091 }
1092
1093 Error ValidateCreateContext(Display *display,
1094                             Config *configuration,
1095                             gl::Context *shareContext,
1096                             const AttributeMap &attributes)
1097 {
1098     if (configuration)
1099     {
1100         ANGLE_TRY(ValidateConfig(display, configuration));
1101     }
1102     else
1103     {
1104         ANGLE_TRY(ValidateDisplay(display));
1105         const DisplayExtensions &displayExtensions = display->getExtensions();
1106         if (!displayExtensions.noConfigContext)
1107         {
1108             return EglBadConfig();
1109         }
1110     }
1111
1112     // Get the requested client version (default is 1) and check it is 2 or 3.
1113     EGLAttrib clientMajorVersion = 1;
1114     EGLAttrib clientMinorVersion = 0;
1115     EGLAttrib contextFlags       = 0;
1116     bool resetNotification       = false;
1117     for (AttributeMap::const_iterator attributeIter = attributes.begin();
1118          attributeIter != attributes.end(); attributeIter++)
1119     {
1120         EGLAttrib attribute = attributeIter->first;
1121         EGLAttrib value     = attributeIter->second;
1122
1123         switch (attribute)
1124         {
1125             case EGL_CONTEXT_CLIENT_VERSION:
1126                 clientMajorVersion = value;
1127                 break;
1128
1129             case EGL_CONTEXT_MINOR_VERSION:
1130                 clientMinorVersion = value;
1131                 break;
1132
1133             case EGL_CONTEXT_FLAGS_KHR:
1134                 contextFlags = value;
1135                 break;
1136
1137             case EGL_CONTEXT_OPENGL_DEBUG:
1138                 break;
1139
1140             case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
1141                 // Only valid for OpenGL (non-ES) contexts
1142                 return EglBadAttribute();
1143
1144             case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
1145                 if (!display->getExtensions().createContextRobustness)
1146                 {
1147                     return EglBadAttribute();
1148                 }
1149                 if (value != EGL_TRUE && value != EGL_FALSE)
1150                 {
1151                     return EglBadAttribute();
1152                 }
1153                 break;
1154
1155             case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
1156                 return EglBadAttribute()
1157                        << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR is not"
1158                        << " valid for GLES with EGL 1.4 and KHR_create_context. Use"
1159                        << " EXT_create_context_robustness.";
1160             case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
1161                 if (!display->getExtensions().createContextRobustness)
1162                 {
1163                     return EglBadAttribute();
1164                 }
1165                 if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT)
1166                 {
1167                     resetNotification = true;
1168                 }
1169                 else if (value != EGL_NO_RESET_NOTIFICATION_EXT)
1170                 {
1171                     return EglBadAttribute();
1172                 }
1173                 break;
1174
1175             case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
1176                 if (!display->getExtensions().createContextNoError)
1177                 {
1178                     return EglBadAttribute() << "Invalid Context attribute.";
1179                 }
1180                 if (value != EGL_TRUE && value != EGL_FALSE)
1181                 {
1182                     return EglBadAttribute() << "Attribute must be EGL_TRUE or EGL_FALSE.";
1183                 }
1184                 break;
1185
1186             case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE:
1187                 if (!display->getExtensions().createContextWebGLCompatibility)
1188                 {
1189                     return EglBadAttribute() << "Attribute "
1190                                                 "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires "
1191                                                 "EGL_ANGLE_create_context_webgl_compatibility.";
1192                 }
1193                 if (value != EGL_TRUE && value != EGL_FALSE)
1194                 {
1195                     return EglBadAttribute() << "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be "
1196                                                 "EGL_TRUE or EGL_FALSE.";
1197                 }
1198                 break;
1199
1200             case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM:
1201                 if (!display->getExtensions().createContextBindGeneratesResource)
1202                 {
1203                     return EglBadAttribute()
1204                            << "Attribute EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM requires "
1205                               "EGL_CHROMIUM_create_context_bind_generates_resource.";
1206                 }
1207                 if (value != EGL_TRUE && value != EGL_FALSE)
1208                 {
1209                     return EglBadAttribute() << "EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM "
1210                                                 "must be EGL_TRUE or EGL_FALSE.";
1211                 }
1212                 break;
1213
1214             case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE:
1215                 if (!display->getExtensions().displayTextureShareGroup)
1216                 {
1217                     return EglBadAttribute() << "Attribute "
1218                                                 "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE requires "
1219                                                 "EGL_ANGLE_display_texture_share_group.";
1220                 }
1221                 if (value != EGL_TRUE && value != EGL_FALSE)
1222                 {
1223                     return EglBadAttribute() << "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE must be "
1224                                                 "EGL_TRUE or EGL_FALSE.";
1225                 }
1226                 if (shareContext &&
1227                     (shareContext->usingDisplayTextureShareGroup() != (value == EGL_TRUE)))
1228                 {
1229                     return EglBadAttribute() << "All contexts within a share group must be "
1230                                                 "created with the same value of "
1231                                                 "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE.";
1232                 }
1233                 break;
1234
1235             case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE:
1236                 if (!display->getExtensions().createContextClientArrays)
1237                 {
1238                     return EglBadAttribute()
1239                            << "Attribute EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE requires "
1240                               "EGL_ANGLE_create_context_client_arrays.";
1241                 }
1242                 if (value != EGL_TRUE && value != EGL_FALSE)
1243                 {
1244                     return EglBadAttribute() << "EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE must "
1245                                                 "be EGL_TRUE or EGL_FALSE.";
1246                 }
1247                 break;
1248
1249             case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE:
1250                 if (!display->getExtensions().programCacheControl)
1251                 {
1252                     return EglBadAttribute()
1253                            << "Attribute EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE "
1254                               "requires EGL_ANGLE_program_cache_control.";
1255                 }
1256                 if (value != EGL_TRUE && value != EGL_FALSE)
1257                 {
1258                     return EglBadAttribute()
1259                            << "EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE must "
1260                               "be EGL_TRUE or EGL_FALSE.";
1261                 }
1262                 break;
1263
1264             case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
1265                 if (!display->getExtensions().robustResourceInitialization)
1266                 {
1267                     return EglBadAttribute()
1268                            << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
1269                               "requires EGL_ANGLE_robust_resource_initialization.";
1270                 }
1271                 if (value != EGL_TRUE && value != EGL_FALSE)
1272                 {
1273                     return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
1274                                                 "either EGL_TRUE or EGL_FALSE.";
1275                 }
1276                 break;
1277
1278             case EGL_EXTENSIONS_ENABLED_ANGLE:
1279                 if (!display->getExtensions().createContextExtensionsEnabled)
1280                 {
1281                     return EglBadAttribute()
1282                            << "Attribute EGL_EXTENSIONS_ENABLED_ANGLE "
1283                               "requires EGL_ANGLE_create_context_extensions_enabled.";
1284                 }
1285                 if (value != EGL_TRUE && value != EGL_FALSE)
1286                 {
1287                     return EglBadAttribute() << "EGL_EXTENSIONS_ENABLED_ANGLE must be "
1288                                                 "either EGL_TRUE or EGL_FALSE.";
1289                 }
1290                 break;
1291
1292             case EGL_POWER_PREFERENCE_ANGLE:
1293                 if (!display->getExtensions().powerPreference)
1294                 {
1295                     return EglBadAttribute() << "Attribute EGL_POWER_PREFERENCE_ANGLE "
1296                                                 "requires EGL_ANGLE_power_preference.";
1297                 }
1298                 if (value != EGL_LOW_POWER_ANGLE && value != EGL_HIGH_POWER_ANGLE)
1299                 {
1300                     return EglBadAttribute()
1301                            << "EGL_POWER_PREFERENCE_ANGLE must be "
1302                               "either EGL_LOW_POWER_ANGLE or EGL_HIGH_POWER_ANGLE.";
1303                 }
1304                 break;
1305
1306             case EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE:
1307                 if (!display->getExtensions().createContextBackwardsCompatible)
1308                 {
1309                     return EglBadAttribute()
1310                            << "Attribute EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE "
1311                               "requires EGL_ANGLE_create_context_backwards_compatible.";
1312                 }
1313                 if (value != EGL_TRUE && value != EGL_FALSE)
1314                 {
1315                     return EglBadAttribute()
1316                            << "EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE must be "
1317                               "either EGL_TRUE or EGL_FALSE.";
1318                 }
1319                 break;
1320
1321             case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
1322                 if (!display->getExtensions().contextPriority)
1323                 {
1324                     return EglBadAttribute() << "Attribute EGL_CONTEXT_PRIORITY_LEVEL_IMG requires "
1325                                                 "extension EGL_IMG_context_priority.";
1326                 }
1327                 switch (value)
1328                 {
1329                     case EGL_CONTEXT_PRIORITY_LOW_IMG:
1330                     case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
1331                     case EGL_CONTEXT_PRIORITY_HIGH_IMG:
1332                         break;
1333                     default:
1334                         return EglBadAttribute() << "Attribute EGL_CONTEXT_PRIORITY_LEVEL_IMG "
1335                                                     "must be one of: EGL_CONTEXT_PRIORITY_LOW_IMG, "
1336                                                     "EGL_CONTEXT_PRIORITY_MEDIUM_IMG, or "
1337                                                     "EGL_CONTEXT_PRIORITY_HIGH_IMG.";
1338                 }
1339                 break;
1340
1341             default:
1342                 return EglBadAttribute() << "Unknown attribute.";
1343         }
1344     }
1345
1346     switch (clientMajorVersion)
1347     {
1348         case 1:
1349             if (clientMinorVersion != 0 && clientMinorVersion != 1)
1350             {
1351                 return EglBadAttribute();
1352             }
1353             if (configuration == EGL_NO_CONFIG_KHR)
1354             {
1355                 return EglBadMatch();
1356             }
1357             if ((configuration != EGL_NO_CONFIG_KHR) &&
1358                 !(configuration->renderableType & EGL_OPENGL_ES_BIT))
1359             {
1360                 return EglBadMatch();
1361             }
1362             break;
1363
1364         case 2:
1365             if (clientMinorVersion != 0)
1366             {
1367                 return EglBadAttribute();
1368             }
1369             if ((configuration != EGL_NO_CONFIG_KHR) &&
1370                 !(configuration->renderableType & EGL_OPENGL_ES2_BIT))
1371             {
1372                 return EglBadMatch();
1373             }
1374             break;
1375         case 3:
1376             if (clientMinorVersion != 0 && clientMinorVersion != 1)
1377             {
1378                 return EglBadAttribute();
1379             }
1380             if ((configuration != EGL_NO_CONFIG_KHR) &&
1381                 !(configuration->renderableType & EGL_OPENGL_ES3_BIT))
1382             {
1383                 return EglBadMatch();
1384             }
1385             if (display->getMaxSupportedESVersion() <
1386                 gl::Version(static_cast<GLuint>(clientMajorVersion),
1387                             static_cast<GLuint>(clientMinorVersion)))
1388             {
1389                 return EglBadAttribute() << "Requested GLES version is not supported.";
1390             }
1391             break;
1392         default:
1393             return EglBadAttribute();
1394             break;
1395     }
1396
1397     // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES
1398     const EGLint validContextFlags =
1399         (EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
1400     if ((contextFlags & ~validContextFlags) != 0)
1401     {
1402         return EglBadAttribute();
1403     }
1404
1405     if (shareContext)
1406     {
1407         // Shared context is invalid or is owned by another display
1408         if (!display->isValidContext(shareContext))
1409         {
1410             return EglBadMatch();
1411         }
1412
1413         if (shareContext->isResetNotificationEnabled() != resetNotification)
1414         {
1415             return EglBadMatch();
1416         }
1417     }
1418
1419     return NoError();
1420 }
1421
1422 Error ValidateCreateWindowSurface(Display *display,
1423                                   Config *config,
1424                                   EGLNativeWindowType window,
1425                                   const AttributeMap &attributes)
1426 {
1427     ANGLE_TRY(ValidateConfig(display, config));
1428
1429     if (!display->isValidNativeWindow(window))
1430     {
1431         return EglBadNativeWindow();
1432     }
1433
1434     const DisplayExtensions &displayExtensions = display->getExtensions();
1435
1436     for (AttributeMap::const_iterator attributeIter = attributes.begin();
1437          attributeIter != attributes.end(); attributeIter++)
1438     {
1439         EGLAttrib attribute = attributeIter->first;
1440         EGLAttrib value     = attributeIter->second;
1441
1442         switch (attribute)
1443         {
1444             case EGL_RENDER_BUFFER:
1445                 switch (value)
1446                 {
1447                     case EGL_BACK_BUFFER:
1448                         break;
1449                     case EGL_SINGLE_BUFFER:
1450                         return EglBadMatch();  // Rendering directly to front buffer not supported
1451                     default:
1452                         return EglBadAttribute();
1453                 }
1454                 break;
1455
1456             case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
1457                 if (!displayExtensions.postSubBuffer)
1458                 {
1459                     return EglBadAttribute();
1460                 }
1461                 break;
1462
1463             case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
1464                 if (!displayExtensions.flexibleSurfaceCompatibility)
1465                 {
1466                     return EglBadAttribute();
1467                 }
1468                 break;
1469
1470             case EGL_WIDTH:
1471             case EGL_HEIGHT:
1472                 if (!displayExtensions.windowFixedSize)
1473                 {
1474                     return EglBadAttribute();
1475                 }
1476                 if (value < 0)
1477                 {
1478                     return EglBadParameter();
1479                 }
1480                 break;
1481
1482             case EGL_FIXED_SIZE_ANGLE:
1483                 if (!displayExtensions.windowFixedSize)
1484                 {
1485                     return EglBadAttribute();
1486                 }
1487                 break;
1488
1489             case EGL_SURFACE_ORIENTATION_ANGLE:
1490                 if (!displayExtensions.surfaceOrientation)
1491                 {
1492                     return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled.";
1493                 }
1494                 break;
1495
1496             case EGL_VG_COLORSPACE:
1497                 return EglBadMatch();
1498
1499             case EGL_GL_COLORSPACE:
1500                 ANGLE_TRY(ValidateColorspaceAttribute(displayExtensions, value));
1501                 break;
1502
1503             case EGL_VG_ALPHA_FORMAT:
1504                 return EglBadMatch();
1505
1506             case EGL_DIRECT_COMPOSITION_ANGLE:
1507                 if (!displayExtensions.directComposition)
1508                 {
1509                     return EglBadAttribute();
1510                 }
1511                 break;
1512
1513             case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
1514                 if (!display->getExtensions().robustResourceInitialization)
1515                 {
1516                     return EglBadAttribute()
1517                            << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
1518                               "requires EGL_ANGLE_robust_resource_initialization.";
1519                 }
1520                 if (value != EGL_TRUE && value != EGL_FALSE)
1521                 {
1522                     return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
1523                                                 "either EGL_TRUE or EGL_FALSE.";
1524                 }
1525                 break;
1526
1527             case EGL_GGP_STREAM_DESCRIPTOR_ANGLE:
1528                 if (!display->getExtensions().ggpStreamDescriptor)
1529                 {
1530                     return EglBadAttribute() << "EGL_GGP_STREAM_DESCRIPTOR_ANGLE requires "
1531                                                 "EGL_ANGLE_ggp_stream_descriptor.";
1532                 }
1533                 break;
1534
1535             default:
1536                 return EglBadAttribute();
1537         }
1538     }
1539
1540     if (Display::hasExistingWindowSurface(window))
1541     {
1542         return EglBadAlloc();
1543     }
1544
1545     return NoError();
1546 }
1547
1548 Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap &attributes)
1549 {
1550     ANGLE_TRY(ValidateConfig(display, config));
1551
1552     const DisplayExtensions &displayExtensions = display->getExtensions();
1553
1554     for (AttributeMap::const_iterator attributeIter = attributes.begin();
1555          attributeIter != attributes.end(); attributeIter++)
1556     {
1557         EGLAttrib attribute = attributeIter->first;
1558         EGLAttrib value     = attributeIter->second;
1559
1560         switch (attribute)
1561         {
1562             case EGL_WIDTH:
1563             case EGL_HEIGHT:
1564                 if (value < 0)
1565                 {
1566                     return EglBadParameter();
1567                 }
1568                 break;
1569
1570             case EGL_LARGEST_PBUFFER:
1571                 break;
1572
1573             case EGL_TEXTURE_FORMAT:
1574                 switch (value)
1575                 {
1576                     case EGL_NO_TEXTURE:
1577                     case EGL_TEXTURE_RGB:
1578                     case EGL_TEXTURE_RGBA:
1579                         break;
1580                     default:
1581                         return EglBadAttribute();
1582                 }
1583                 break;
1584
1585             case EGL_TEXTURE_TARGET:
1586                 switch (value)
1587                 {
1588                     case EGL_NO_TEXTURE:
1589                     case EGL_TEXTURE_2D:
1590                         break;
1591                     default:
1592                         return EglBadAttribute();
1593                 }
1594                 break;
1595
1596             case EGL_MIPMAP_TEXTURE:
1597                 break;
1598
1599             case EGL_VG_COLORSPACE:
1600                 break;
1601
1602             case EGL_GL_COLORSPACE:
1603                 ANGLE_TRY(ValidateColorspaceAttribute(displayExtensions, value));
1604                 break;
1605
1606             case EGL_VG_ALPHA_FORMAT:
1607                 break;
1608
1609             case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
1610                 if (!displayExtensions.flexibleSurfaceCompatibility)
1611                 {
1612                     return EglBadAttribute()
1613                            << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used "
1614                               "without EGL_ANGLE_flexible_surface_compatibility support.";
1615                 }
1616                 break;
1617
1618             case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
1619                 if (!display->getExtensions().robustResourceInitialization)
1620                 {
1621                     return EglBadAttribute()
1622                            << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
1623                               "requires EGL_ANGLE_robust_resource_initialization.";
1624                 }
1625                 if (value != EGL_TRUE && value != EGL_FALSE)
1626                 {
1627                     return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
1628                                                 "either EGL_TRUE or EGL_FALSE.";
1629                 }
1630                 break;
1631
1632             default:
1633                 return EglBadAttribute();
1634         }
1635     }
1636
1637     if (!(config->surfaceType & EGL_PBUFFER_BIT))
1638     {
1639         return EglBadMatch();
1640     }
1641
1642     const Caps &caps = display->getCaps();
1643
1644     EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
1645     EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
1646
1647     if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
1648         (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
1649     {
1650         return EglBadMatch();
1651     }
1652
1653     if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) ||
1654         (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
1655     {
1656         return EglBadAttribute();
1657     }
1658
1659     EGLint width  = static_cast<EGLint>(attributes.get(EGL_WIDTH, 0));
1660     EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, 0));
1661     if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT &&
1662         (!gl::isPow2(width) || !gl::isPow2(height)))
1663     {
1664         return EglBadMatch();
1665     }
1666
1667     return NoError();
1668 }
1669
1670 Error ValidateCreatePbufferFromClientBuffer(Display *display,
1671                                             EGLenum buftype,
1672                                             EGLClientBuffer buffer,
1673                                             Config *config,
1674                                             const AttributeMap &attributes)
1675 {
1676     ANGLE_TRY(ValidateConfig(display, config));
1677
1678     const DisplayExtensions &displayExtensions = display->getExtensions();
1679
1680     switch (buftype)
1681     {
1682         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
1683             if (!displayExtensions.d3dShareHandleClientBuffer)
1684             {
1685                 return EglBadParameter();
1686             }
1687             if (buffer == nullptr)
1688             {
1689                 return EglBadParameter();
1690             }
1691             break;
1692
1693         case EGL_D3D_TEXTURE_ANGLE:
1694             if (!displayExtensions.d3dTextureClientBuffer)
1695             {
1696                 return EglBadParameter();
1697             }
1698             if (buffer == nullptr)
1699             {
1700                 return EglBadParameter();
1701             }
1702             break;
1703
1704         case EGL_IOSURFACE_ANGLE:
1705             if (!displayExtensions.iosurfaceClientBuffer)
1706             {
1707                 return EglBadParameter() << "<buftype> EGL_IOSURFACE_ANGLE requires the "
1708                                             "EGL_ANGLE_iosurface_client_buffer extension.";
1709             }
1710             if (buffer == nullptr)
1711             {
1712                 return EglBadParameter() << "<buffer> must be non null";
1713             }
1714             break;
1715
1716         default:
1717             return EglBadParameter();
1718     }
1719
1720     for (AttributeMap::const_iterator attributeIter = attributes.begin();
1721          attributeIter != attributes.end(); attributeIter++)
1722     {
1723         EGLAttrib attribute = attributeIter->first;
1724         EGLAttrib value     = attributeIter->second;
1725
1726         switch (attribute)
1727         {
1728             case EGL_WIDTH:
1729             case EGL_HEIGHT:
1730                 if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE &&
1731                     buftype != EGL_D3D_TEXTURE_ANGLE && buftype != EGL_IOSURFACE_ANGLE)
1732                 {
1733                     return EglBadParameter()
1734                            << "Width and Height are not supported for thie <buftype>";
1735                 }
1736                 if (value < 0)
1737                 {
1738                     return EglBadParameter() << "Width and Height must be positive";
1739                 }
1740                 break;
1741
1742             case EGL_TEXTURE_FORMAT:
1743                 switch (value)
1744                 {
1745                     case EGL_NO_TEXTURE:
1746                     case EGL_TEXTURE_RGB:
1747                     case EGL_TEXTURE_RGBA:
1748                         break;
1749                     default:
1750                         return EglBadAttribute() << "Invalid value for EGL_TEXTURE_FORMAT";
1751                 }
1752                 break;
1753
1754             case EGL_TEXTURE_TARGET:
1755                 switch (value)
1756                 {
1757                     case EGL_NO_TEXTURE:
1758                     case EGL_TEXTURE_2D:
1759                         break;
1760                     case EGL_TEXTURE_RECTANGLE_ANGLE:
1761                         if (buftype != EGL_IOSURFACE_ANGLE)
1762                         {
1763                             return EglBadParameter()
1764                                    << "<buftype> doesn't support rectangle texture targets";
1765                         }
1766                         break;
1767
1768                     default:
1769                         return EglBadAttribute() << "Invalid value for EGL_TEXTURE_TARGET";
1770                 }
1771                 break;
1772
1773             case EGL_MIPMAP_TEXTURE:
1774                 break;
1775
1776             case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
1777                 if (!displayExtensions.flexibleSurfaceCompatibility)
1778                 {
1779                     return EglBadAttribute()
1780                            << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used "
1781                               "without EGL_ANGLE_flexible_surface_compatibility support.";
1782                 }
1783                 break;
1784
1785             case EGL_IOSURFACE_PLANE_ANGLE:
1786                 if (buftype != EGL_IOSURFACE_ANGLE)
1787                 {
1788                     return EglBadAttribute() << "<buftype> doesn't support iosurface plane";
1789                 }
1790                 break;
1791
1792             case EGL_TEXTURE_TYPE_ANGLE:
1793                 if (buftype != EGL_IOSURFACE_ANGLE)
1794                 {
1795                     return EglBadAttribute() << "<buftype> doesn't support texture type";
1796                 }
1797                 break;
1798
1799             case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
1800                 if (buftype != EGL_IOSURFACE_ANGLE && buftype != EGL_D3D_TEXTURE_ANGLE)
1801                 {
1802                     return EglBadAttribute() << "<buftype> doesn't support texture internal format";
1803                 }
1804                 break;
1805             case EGL_GL_COLORSPACE:
1806                 if (buftype != EGL_D3D_TEXTURE_ANGLE)
1807                 {
1808                     return EglBadAttribute() << "<buftype> doesn't support setting GL colorspace";
1809                 }
1810                 break;
1811             case EGL_IOSURFACE_USAGE_HINT_ANGLE:
1812                 if (value & ~(EGL_IOSURFACE_READ_HINT_ANGLE | EGL_IOSURFACE_WRITE_HINT_ANGLE))
1813                 {
1814                     return EglBadAttribute()
1815                            << "IOSurface usage hint must only contain READ or WRITE";
1816                 }
1817                 break;
1818             default:
1819                 return EglBadAttribute();
1820         }
1821     }
1822
1823     EGLAttrib colorspace = attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR);
1824     if (colorspace != EGL_GL_COLORSPACE_LINEAR && colorspace != EGL_GL_COLORSPACE_SRGB)
1825     {
1826         return EglBadAttribute() << "invalid GL colorspace";
1827     }
1828
1829     if (!(config->surfaceType & EGL_PBUFFER_BIT))
1830     {
1831         return EglBadMatch();
1832     }
1833
1834     EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
1835     EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
1836     if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
1837         (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
1838     {
1839         return EglBadMatch();
1840     }
1841     if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) ||
1842         (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
1843     {
1844         // TODO(cwallez@chromium.org): For IOSurface pbuffers we require that EGL_TEXTURE_RGBA is
1845         // set so that eglBindTexImage works. Normally this is only allowed if the config exposes
1846         // the bindToTextureRGB/RGBA flag. This issue is that enabling this flags means that
1847         // eglBindTexImage should also work for regular pbuffers which isn't implemented on macOS.
1848         // Instead of adding the flag we special case the check here to be ignored for IOSurfaces.
1849         // The TODO is to find a proper solution for this, maybe by implementing eglBindTexImage on
1850         // OSX?
1851         if (buftype != EGL_IOSURFACE_ANGLE)
1852         {
1853             return EglBadAttribute();
1854         }
1855     }
1856
1857     if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
1858     {
1859         EGLint width  = static_cast<EGLint>(attributes.get(EGL_WIDTH, 0));
1860         EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, 0));
1861
1862         if (width == 0 || height == 0)
1863         {
1864             return EglBadAttribute();
1865         }
1866
1867         const Caps &caps = display->getCaps();
1868         if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT &&
1869             (!gl::isPow2(width) || !gl::isPow2(height)))
1870         {
1871             return EglBadMatch();
1872         }
1873     }
1874
1875     if (buftype == EGL_IOSURFACE_ANGLE)
1876     {
1877 #if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
1878         if (textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE)
1879         {
1880             return EglBadAttribute()
1881                    << "EGL_IOSURFACE requires the EGL_TEXTURE_RECTANGLE target on desktop macOS";
1882         }
1883 #else // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
1884         if (textureTarget != EGL_TEXTURE_2D)
1885         {
1886             return EglBadAttribute() << "EGL_IOSURFACE requires the EGL_TEXTURE_2D target on iOS";
1887         }
1888 #endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
1889
1890         if (textureFormat != EGL_TEXTURE_RGBA)
1891         {
1892             return EglBadAttribute() << "EGL_IOSURFACE requires the EGL_TEXTURE_RGBA format";
1893         }
1894
1895         if (!attributes.contains(EGL_WIDTH) || !attributes.contains(EGL_HEIGHT) ||
1896             !attributes.contains(EGL_TEXTURE_FORMAT) ||
1897             !attributes.contains(EGL_TEXTURE_TYPE_ANGLE) ||
1898             !attributes.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE) ||
1899             !attributes.contains(EGL_IOSURFACE_PLANE_ANGLE))
1900         {
1901             return EglBadParameter() << "Missing required attribute for EGL_IOSURFACE";
1902         }
1903     }
1904
1905     ANGLE_TRY(display->validateClientBuffer(config, buftype, buffer, attributes));
1906
1907     return NoError();
1908 }
1909
1910 Error ValidateMakeCurrent(Display *display, Surface *draw, Surface *read, gl::Context *context)
1911 {
1912     if (context == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
1913     {
1914         return EglBadMatch() << "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE";
1915     }
1916
1917     // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH
1918     // error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE.
1919     if (context != EGL_NO_CONTEXT && (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE))
1920     {
1921         if (display->getExtensions().surfacelessContext)
1922         {
1923             if ((draw == EGL_NO_SURFACE) != (read == EGL_NO_SURFACE))
1924             {
1925                 return EglBadMatch() << "If ctx is not EGL_NOT_CONTEXT, draw or read must "
1926                                         "both be EGL_NO_SURFACE, or both not";
1927             }
1928         }
1929         else
1930         {
1931             return EglBadMatch()
1932                    << "If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE";
1933         }
1934     }
1935
1936     // If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an
1937     // EGL_BAD_MATCH error is generated.
1938     if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE))
1939     {
1940         return EglBadMatch()
1941                << "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE";
1942     }
1943
1944     if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
1945     {
1946         return EglBadDisplay() << "'dpy' not a valid EGLDisplay handle";
1947     }
1948
1949     // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null
1950     if (!display->isInitialized() &&
1951         (context != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
1952     {
1953         return EglNotInitialized() << "'dpy' not initialized";
1954     }
1955
1956     if (context != EGL_NO_CONTEXT)
1957     {
1958         ANGLE_TRY(ValidateContext(display, context));
1959     }
1960
1961     if (display->isInitialized() && display->isDeviceLost())
1962     {
1963         return EglContextLost();
1964     }
1965
1966     if (draw != EGL_NO_SURFACE)
1967     {
1968         ANGLE_TRY(ValidateSurface(display, draw));
1969     }
1970
1971     if (read != EGL_NO_SURFACE)
1972     {
1973         ANGLE_TRY(ValidateSurface(display, read));
1974         ANGLE_TRY(ValidateCompatibleSurface(display, context, read));
1975     }
1976
1977     if (draw != read)
1978     {
1979         if (draw)
1980         {
1981             ANGLE_TRY(ValidateCompatibleSurface(display, context, draw));
1982         }
1983         if (read)
1984         {
1985             ANGLE_TRY(ValidateCompatibleSurface(display, context, read));
1986         }
1987     }
1988     return NoError();
1989 }
1990
1991 Error ValidateCompatibleSurface(const Display *display,
1992                                 gl::Context *context,
1993                                 const Surface *surface)
1994 {
1995     const Config *contextConfig = context->getConfig();
1996     const Config *surfaceConfig = surface->getConfig();
1997
1998     // Surface compatible with client API - only OPENGL_ES supported
1999     switch (context->getClientMajorVersion())
2000     {
2001         case 1:
2002             if (!(surfaceConfig->renderableType & EGL_OPENGL_ES_BIT))
2003             {
2004                 return EglBadMatch() << "Surface not compatible with OpenGL ES 1.x.";
2005             }
2006             break;
2007         case 2:
2008             if (!(surfaceConfig->renderableType & EGL_OPENGL_ES2_BIT))
2009             {
2010                 return EglBadMatch() << "Surface not compatible with OpenGL ES 2.x.";
2011             }
2012             break;
2013         case 3:
2014             if (!(surfaceConfig->renderableType & (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT)))
2015             {
2016                 return EglBadMatch() << "Surface not compatible with OpenGL ES 3.x.";
2017             }
2018             break;
2019         default:
2020             return EglBadMatch() << "Surface not compatible with Context API.";
2021     }
2022
2023     // EGL KHR no config context
2024     if (context->getConfig() == EGL_NO_CONFIG_KHR)
2025     {
2026         const DisplayExtensions &displayExtensions = display->getExtensions();
2027         if (displayExtensions.noConfigContext)
2028         {
2029             return NoError();
2030         }
2031         return EglBadMatch() << "Context with no config is not supported.";
2032     }
2033
2034     if (!surface->flexibleSurfaceCompatibilityRequested())
2035     {
2036         // Config compatibility is defined in section 2.2 of the EGL 1.5 spec
2037
2038         bool colorBufferCompat = surfaceConfig->colorBufferType == contextConfig->colorBufferType;
2039         if (!colorBufferCompat)
2040         {
2041             return EglBadMatch() << "Color buffer types are not compatible.";
2042         }
2043
2044         bool colorCompat = surfaceConfig->redSize == contextConfig->redSize &&
2045                            surfaceConfig->greenSize == contextConfig->greenSize &&
2046                            surfaceConfig->blueSize == contextConfig->blueSize &&
2047                            surfaceConfig->alphaSize == contextConfig->alphaSize &&
2048                            surfaceConfig->luminanceSize == contextConfig->luminanceSize;
2049         if (!colorCompat)
2050         {
2051             return EglBadMatch() << "Color buffer sizes are not compatible.";
2052         }
2053
2054         bool componentTypeCompat =
2055             surfaceConfig->colorComponentType == contextConfig->colorComponentType;
2056         if (!componentTypeCompat)
2057         {
2058             return EglBadMatch() << "Color buffer component types are not compatible.";
2059         }
2060
2061         bool dsCompat = surfaceConfig->depthSize == contextConfig->depthSize &&
2062                         surfaceConfig->stencilSize == contextConfig->stencilSize;
2063         if (!dsCompat)
2064         {
2065             return EglBadMatch() << "Depth-stencil buffer types are not compatible.";
2066         }
2067     }
2068
2069     bool surfaceTypeCompat = (surfaceConfig->surfaceType & contextConfig->surfaceType) != 0;
2070     if (!surfaceTypeCompat)
2071     {
2072         return EglBadMatch() << "Surface type is not compatible.";
2073     }
2074
2075     return NoError();
2076 }
2077
2078 Error ValidateCreateImage(const Display *display,
2079                           gl::Context *context,
2080                           EGLenum target,
2081                           EGLClientBuffer buffer,
2082                           const AttributeMap &attributes)
2083 {
2084
2085     ANGLE_TRY(ValidateDisplay(display));
2086
2087     const DisplayExtensions &displayExtensions = display->getExtensions();
2088
2089     // TODO(geofflang): Complete validation from EGL_KHR_image_base:
2090     // If the resource specified by <dpy>, <ctx>, <target>, <buffer> and <attrib_list> is itself an
2091     // EGLImage sibling, the error EGL_BAD_ACCESS is generated.
2092
2093     for (AttributeMap::const_iterator attributeIter = attributes.begin();
2094          attributeIter != attributes.end(); attributeIter++)
2095     {
2096         EGLAttrib attribute = attributeIter->first;
2097         EGLAttrib value     = attributeIter->second;
2098
2099         switch (attribute)
2100         {
2101             case EGL_IMAGE_PRESERVED:
2102                 switch (value)
2103                 {
2104                     case EGL_TRUE:
2105                     case EGL_FALSE:
2106                         break;
2107
2108                     default:
2109                         return EglBadParameter()
2110                                << "EGL_IMAGE_PRESERVED must be EGL_TRUE or EGL_FALSE.";
2111                 }
2112                 break;
2113
2114             case EGL_GL_TEXTURE_LEVEL:
2115                 if (!displayExtensions.glTexture2DImage &&
2116                     !displayExtensions.glTextureCubemapImage && !displayExtensions.glTexture3DImage)
2117                 {
2118                     return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL cannot be used "
2119                                                 "without KHR_gl_texture_*_image support.";
2120                 }
2121
2122                 if (value < 0)
2123                 {
2124                     return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL cannot be negative.";
2125                 }
2126                 break;
2127
2128             case EGL_GL_TEXTURE_ZOFFSET:
2129                 if (!displayExtensions.glTexture3DImage)
2130                 {
2131                     return EglBadParameter() << "EGL_GL_TEXTURE_ZOFFSET cannot be used "
2132                                                 "without KHR_gl_texture_3D_image support.";
2133                 }
2134                 break;
2135
2136             case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
2137                 if (!displayExtensions.imageD3D11Texture)
2138                 {
2139                     return EglBadParameter()
2140                            << "EGL_TEXTURE_INTERNAL_FORMAT_ANGLE and EGL_TEXTURE_TYPE_ANGLE cannot "
2141                               "be used without EGL_ANGLE_image_d3d11_texture support.";
2142                 }
2143                 break;
2144
2145             default:
2146                 return EglBadParameter()
2147                        << "invalid attribute: 0x" << std::hex << std::uppercase << attribute;
2148         }
2149     }
2150
2151     switch (target)
2152     {
2153         case EGL_GL_TEXTURE_2D:
2154         {
2155             if (!displayExtensions.glTexture2DImage)
2156             {
2157                 return EglBadParameter() << "KHR_gl_texture_2D_image not supported.";
2158             }
2159
2160             if (buffer == 0)
2161             {
2162                 return EglBadParameter() << "buffer cannot reference a 2D texture with the name 0.";
2163             }
2164
2165             ANGLE_TRY(ValidateContext(display, context));
2166             const gl::Texture *texture =
2167                 context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
2168             if (texture == nullptr || texture->getType() != gl::TextureType::_2D)
2169             {
2170                 return EglBadParameter() << "target is not a 2D texture.";
2171             }
2172
2173             if (texture->getBoundSurface() != nullptr)
2174             {
2175                 return EglBadAccess() << "texture has a surface bound to it.";
2176             }
2177
2178             EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL, 0);
2179             if (texture->getWidth(gl::TextureTarget::_2D, static_cast<size_t>(level)) == 0 ||
2180                 texture->getHeight(gl::TextureTarget::_2D, static_cast<size_t>(level)) == 0)
2181             {
2182                 return EglBadParameter()
2183                        << "target 2D texture does not have a valid size at specified level.";
2184             }
2185
2186             ANGLE_TRY(ValidateCreateImageMipLevelCommon(context, texture, level));
2187         }
2188         break;
2189
2190         case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2191         case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2192         case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2193         case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2194         case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2195         case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2196         {
2197             if (!displayExtensions.glTextureCubemapImage)
2198             {
2199                 return EglBadParameter() << "KHR_gl_texture_cubemap_image not supported.";
2200             }
2201
2202             if (buffer == 0)
2203             {
2204                 return EglBadParameter()
2205                        << "buffer cannot reference a cubemap texture with the name 0.";
2206             }
2207
2208             ANGLE_TRY(ValidateContext(display, context));
2209             const gl::Texture *texture =
2210                 context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
2211             if (texture == nullptr || texture->getType() != gl::TextureType::CubeMap)
2212             {
2213                 return EglBadParameter() << "target is not a cubemap texture.";
2214             }
2215
2216             if (texture->getBoundSurface() != nullptr)
2217             {
2218                 return EglBadAccess() << "texture has a surface bound to it.";
2219             }
2220
2221             EGLAttrib level               = attributes.get(EGL_GL_TEXTURE_LEVEL, 0);
2222             gl::TextureTarget cubeMapFace = egl_gl::EGLCubeMapTargetToCubeMapTarget(target);
2223             if (texture->getWidth(cubeMapFace, static_cast<size_t>(level)) == 0 ||
2224                 texture->getHeight(cubeMapFace, static_cast<size_t>(level)) == 0)
2225             {
2226                 return EglBadParameter() << "target cubemap texture does not have a valid "
2227                                             "size at specified level and face.";
2228             }
2229
2230             ANGLE_TRY(ValidateCreateImageMipLevelCommon(context, texture, level));
2231
2232             if (level == 0 && !texture->isMipmapComplete() &&
2233                 CubeTextureHasUnspecifiedLevel0Face(texture))
2234             {
2235                 return EglBadParameter() << "if level is zero and the texture is incomplete, "
2236                                             "it must have all of its faces specified at level "
2237                                             "zero.";
2238             }
2239         }
2240         break;
2241
2242         case EGL_GL_TEXTURE_3D:
2243         {
2244             if (!displayExtensions.glTexture3DImage)
2245             {
2246                 return EglBadParameter() << "KHR_gl_texture_3D_image not supported.";
2247             }
2248
2249             if (buffer == 0)
2250             {
2251                 return EglBadParameter() << "buffer cannot reference a 3D texture with the name 0.";
2252             }
2253
2254             ANGLE_TRY(ValidateContext(display, context));
2255             const gl::Texture *texture =
2256                 context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
2257             if (texture == nullptr || texture->getType() != gl::TextureType::_3D)
2258             {
2259                 return EglBadParameter() << "target is not a 3D texture.";
2260             }
2261
2262             if (texture->getBoundSurface() != nullptr)
2263             {
2264                 return EglBadAccess() << "texture has a surface bound to it.";
2265             }
2266
2267             EGLAttrib level   = attributes.get(EGL_GL_TEXTURE_LEVEL, 0);
2268             EGLAttrib zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET, 0);
2269             if (texture->getWidth(gl::TextureTarget::_3D, static_cast<size_t>(level)) == 0 ||
2270                 texture->getHeight(gl::TextureTarget::_3D, static_cast<size_t>(level)) == 0 ||
2271                 texture->getDepth(gl::TextureTarget::_3D, static_cast<size_t>(level)) == 0)
2272             {
2273                 return EglBadParameter()
2274                        << "target 3D texture does not have a valid size at specified level.";
2275             }
2276
2277             if (static_cast<size_t>(zOffset) >=
2278                 texture->getDepth(gl::TextureTarget::_3D, static_cast<size_t>(level)))
2279             {
2280                 return EglBadParameter() << "target 3D texture does not have enough layers "
2281                                             "for the specified Z offset at the specified "
2282                                             "level.";
2283             }
2284
2285             ANGLE_TRY(ValidateCreateImageMipLevelCommon(context, texture, level));
2286         }
2287         break;
2288
2289         case EGL_GL_RENDERBUFFER:
2290         {
2291             if (!displayExtensions.glRenderbufferImage)
2292             {
2293                 return EglBadParameter() << "KHR_gl_renderbuffer_image not supported.";
2294             }
2295
2296             if (attributes.contains(EGL_GL_TEXTURE_LEVEL))
2297             {
2298                 return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL cannot be used in "
2299                                             "conjunction with a renderbuffer target.";
2300             }
2301
2302             if (buffer == 0)
2303             {
2304                 return EglBadParameter()
2305                        << "buffer cannot reference a renderbuffer with the name 0.";
2306             }
2307
2308             ANGLE_TRY(ValidateContext(display, context));
2309             const gl::Renderbuffer *renderbuffer =
2310                 context->getRenderbuffer({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
2311             if (renderbuffer == nullptr)
2312             {
2313                 return EglBadParameter() << "target is not a renderbuffer.";
2314             }
2315
2316             if (renderbuffer->getSamples() > 0)
2317             {
2318                 return EglBadParameter() << "target renderbuffer cannot be multisampled.";
2319             }
2320         }
2321         break;
2322
2323         case EGL_NATIVE_BUFFER_ANDROID:
2324         {
2325             if (!displayExtensions.imageNativeBuffer)
2326             {
2327                 return EglBadParameter() << "EGL_ANDROID_image_native_buffer not supported.";
2328             }
2329
2330             if (context != nullptr)
2331             {
2332                 return EglBadContext() << "ctx must be EGL_NO_CONTEXT.";
2333             }
2334
2335             ANGLE_TRY(display->validateImageClientBuffer(context, target, buffer, attributes));
2336         }
2337         break;
2338
2339         case EGL_D3D11_TEXTURE_ANGLE:
2340             if (!displayExtensions.imageD3D11Texture)
2341             {
2342                 return EglBadParameter() << "EGL_ANGLE_image_d3d11_texture not supported.";
2343             }
2344
2345             if (context != nullptr)
2346             {
2347                 return EglBadContext() << "ctx must be EGL_NO_CONTEXT.";
2348             }
2349
2350             ANGLE_TRY(display->validateImageClientBuffer(context, target, buffer, attributes));
2351             break;
2352
2353         default:
2354             return EglBadParameter()
2355                    << "invalid target: 0x" << std::hex << std::uppercase << target;
2356     }
2357
2358     if (attributes.contains(EGL_GL_TEXTURE_ZOFFSET) && target != EGL_GL_TEXTURE_3D)
2359     {
2360         return EglBadParameter() << "EGL_GL_TEXTURE_ZOFFSET must be used with a 3D texture target.";
2361     }
2362
2363     return NoError();
2364 }
2365
2366 Error ValidateDestroyImage(const Display *display, const Image *image)
2367 {
2368     ANGLE_TRY(ValidateImage(display, image));
2369
2370     return NoError();
2371 }
2372
2373 Error ValidateCreateImageKHR(const Display *display,
2374                              gl::Context *context,
2375                              EGLenum target,
2376                              EGLClientBuffer buffer,
2377                              const AttributeMap &attributes)
2378 {
2379     ANGLE_TRY(ValidateDisplay(display));
2380
2381     if (!display->getExtensions().imageBase && !display->getExtensions().image)
2382     {
2383         // It is out of spec what happens when calling an extension function when the extension is
2384         // not available.
2385         // EGL_BAD_DISPLAY seems like a reasonable error.
2386         return EglBadDisplay() << "EGL_KHR_image not supported.";
2387     }
2388
2389     return ValidateCreateImage(display, context, target, buffer, attributes);
2390 }
2391
2392 Error ValidateDestroyImageKHR(const Display *display, const Image *image)
2393 {
2394     ANGLE_TRY(ValidateImage(display, image));
2395
2396     if (!display->getExtensions().imageBase && !display->getExtensions().image)
2397     {
2398         // It is out of spec what happens when calling an extension function when the extension is
2399         // not available.
2400         // EGL_BAD_DISPLAY seems like a reasonable error.
2401         return EglBadDisplay();
2402     }
2403
2404     return NoError();
2405 }
2406
2407 Error ValidateCreateDeviceANGLE(EGLint device_type,
2408                                 void *native_device,
2409                                 const EGLAttrib *attrib_list)
2410 {
2411     const ClientExtensions &clientExtensions = Display::GetClientExtensions();
2412     if (!clientExtensions.deviceCreation)
2413     {
2414         return EglBadAccess() << "Device creation extension not active";
2415     }
2416
2417     if (attrib_list != nullptr && attrib_list[0] != EGL_NONE)
2418     {
2419         return EglBadAttribute() << "Invalid attrib_list parameter";
2420     }
2421
2422     switch (device_type)
2423     {
2424         case EGL_D3D11_DEVICE_ANGLE:
2425             if (!clientExtensions.deviceCreationD3D11)
2426             {
2427                 return EglBadAttribute() << "D3D11 device creation extension not active";
2428             }
2429             break;
2430         default:
2431             return EglBadAttribute() << "Invalid device_type parameter";
2432     }
2433
2434     return NoError();
2435 }
2436
2437 Error ValidateReleaseDeviceANGLE(Device *device)
2438 {
2439     const ClientExtensions &clientExtensions = Display::GetClientExtensions();
2440     if (!clientExtensions.deviceCreation)
2441     {
2442         return EglBadAccess() << "Device creation extension not active";
2443     }
2444
2445     if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device))
2446     {
2447         return EglBadDevice() << "Invalid device parameter";
2448     }
2449
2450     Display *owningDisplay = device->getOwningDisplay();
2451     if (owningDisplay != nullptr)
2452     {
2453         return EglBadDevice() << "Device must have been created using eglCreateDevice";
2454     }
2455
2456     return NoError();
2457 }
2458
2459 Error ValidateCreateSyncBase(const Display *display,
2460                              EGLenum type,
2461                              const AttributeMap &attribs,
2462                              const Display *currentDisplay,
2463                              const gl::Context *currentContext,
2464                              bool isExt)
2465 {
2466     ANGLE_TRY(ValidateDisplay(display));
2467
2468     switch (type)
2469     {
2470         case EGL_SYNC_FENCE_KHR:
2471             if (!attribs.isEmpty())
2472             {
2473                 return EglBadAttribute() << "Invalid attribute";
2474             }
2475             break;
2476
2477         case EGL_SYNC_NATIVE_FENCE_ANDROID:
2478             if (!display->getExtensions().nativeFenceSyncANDROID)
2479             {
2480                 return EglBadDisplay()
2481                        << "EGL_ANDROID_native_fence_sync extension is not available.";
2482             }
2483
2484             for (const auto &attributeIter : attribs)
2485             {
2486                 EGLAttrib attribute = attributeIter.first;
2487
2488                 switch (attribute)
2489                 {
2490                     case EGL_SYNC_NATIVE_FENCE_FD_ANDROID:
2491                         break;
2492
2493                     default:
2494                         return EglBadAttribute() << "Invalid attribute";
2495                 }
2496             }
2497             break;
2498
2499         default:
2500             if (isExt)
2501             {
2502                 return EglBadAttribute() << "Invalid type parameter";
2503             }
2504             else
2505             {
2506                 return EglBadParameter() << "Invalid type parameter";
2507             }
2508     }
2509
2510     if (display != currentDisplay)
2511     {
2512         return EglBadMatch() << "CreateSync can only be called on the current display";
2513     }
2514
2515     ANGLE_TRY(ValidateContext(currentDisplay, currentContext));
2516
2517     if (!currentContext->getExtensions().eglSyncOES)
2518     {
2519         return EglBadMatch() << "EGL_SYNC_FENCE_KHR cannot be used without "
2520                                 "GL_OES_EGL_sync support.";
2521     }
2522
2523     return NoError();
2524 }
2525
2526 Error ValidateGetSyncAttribBase(const Display *display, const Sync *sync, EGLint attribute)
2527 {
2528     ANGLE_TRY(ValidateSync(display, sync));
2529
2530     switch (attribute)
2531     {
2532         case EGL_SYNC_CONDITION_KHR:
2533             switch (sync->getType())
2534             {
2535                 case EGL_SYNC_FENCE_KHR:
2536                 case EGL_SYNC_NATIVE_FENCE_ANDROID:
2537                     break;
2538
2539                 default:
2540                     return EglBadAttribute()
2541                            << "EGL_SYNC_CONDITION_KHR is not valid for this sync type.";
2542             }
2543             break;
2544
2545         // The following attributes are accepted by all types
2546         case EGL_SYNC_TYPE_KHR:
2547         case EGL_SYNC_STATUS_KHR:
2548             break;
2549
2550         default:
2551             return EglBadAttribute() << "Invalid attribute";
2552     }
2553
2554     return NoError();
2555 }
2556
2557 Error ValidateCreateSyncKHR(const Display *display,
2558                             EGLenum type,
2559                             const AttributeMap &attribs,
2560                             const Display *currentDisplay,
2561                             const gl::Context *currentContext)
2562 {
2563     ANGLE_TRY(ValidateDisplay(display));
2564
2565     const DisplayExtensions &extensions = display->getExtensions();
2566     if (!extensions.fenceSync)
2567     {
2568         return EglBadAccess() << "EGL_KHR_fence_sync extension is not available";
2569     }
2570
2571     return ValidateCreateSyncBase(display, type, attribs, currentDisplay, currentContext, true);
2572 }
2573
2574 Error ValidateCreateSync(const Display *display,
2575                          EGLenum type,
2576                          const AttributeMap &attribs,
2577                          const Display *currentDisplay,
2578                          const gl::Context *currentContext)
2579 {
2580     return ValidateCreateSyncBase(display, type, attribs, currentDisplay, currentContext, false);
2581 }
2582
2583 Error ValidateDestroySync(const Display *display, const Sync *sync)
2584 {
2585     ANGLE_TRY(ValidateSync(display, sync));
2586     return NoError();
2587 }
2588
2589 Error ValidateClientWaitSync(const Display *display,
2590                              const Sync *sync,
2591                              EGLint flags,
2592                              EGLTime timeout)
2593 {
2594     ANGLE_TRY(ValidateSync(display, sync));
2595     return NoError();
2596 }
2597
2598 Error ValidateWaitSync(const Display *display,
2599                        const gl::Context *context,
2600                        const Sync *sync,
2601                        EGLint flags)
2602 {
2603     ANGLE_TRY(ValidateDisplay(display));
2604
2605     const DisplayExtensions &extensions = display->getExtensions();
2606     if (!extensions.waitSync)
2607     {
2608         return EglBadAccess() << "EGL_KHR_wait_sync extension is not available";
2609     }
2610
2611     ANGLE_TRY(ValidateSync(display, sync));
2612
2613     if (context == nullptr)
2614     {
2615         return EglBadMatch() << "No context is current.";
2616     }
2617
2618     if (!context->getExtensions().eglSyncOES)
2619     {
2620         return EglBadMatch() << "Server-side waits cannot be performed without "
2621                                 "GL_OES_EGL_sync support.";
2622     }
2623
2624     if (flags != 0)
2625     {
2626         return EglBadParameter() << "flags must be zero";
2627     }
2628
2629     return NoError();
2630 }
2631
2632 Error ValidateGetSyncAttribKHR(const Display *display,
2633                                const Sync *sync,
2634                                EGLint attribute,
2635                                EGLint *value)
2636 {
2637     if (value == nullptr)
2638     {
2639         return EglBadParameter() << "Invalid value parameter";
2640     }
2641     return ValidateGetSyncAttribBase(display, sync, attribute);
2642 }
2643
2644 Error ValidateGetSyncAttrib(const Display *display,
2645                             const Sync *sync,
2646                             EGLint attribute,
2647                             EGLAttrib *value)
2648 {
2649     if (value == nullptr)
2650     {
2651         return EglBadParameter() << "Invalid value parameter";
2652     }
2653     return ValidateGetSyncAttribBase(display, sync, attribute);
2654 }
2655
2656 Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes)
2657 {
2658     ANGLE_TRY(ValidateDisplay(display));
2659
2660     const DisplayExtensions &displayExtensions = display->getExtensions();
2661     if (!displayExtensions.stream)
2662     {
2663         return EglBadAlloc() << "Stream extension not active";
2664     }
2665
2666     for (const auto &attributeIter : attributes)
2667     {
2668         EGLAttrib attribute = attributeIter.first;
2669         EGLAttrib value     = attributeIter.second;
2670
2671         ANGLE_TRY(ValidateStreamAttribute(attribute, value, displayExtensions));
2672     }
2673
2674     return NoError();
2675 }
2676
2677 Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream)
2678 {
2679     ANGLE_TRY(ValidateStream(display, stream));
2680     return NoError();
2681 }
2682
2683 Error ValidateStreamAttribKHR(const Display *display,
2684                               const Stream *stream,
2685                               EGLint attribute,
2686                               EGLint value)
2687 {
2688     ANGLE_TRY(ValidateStream(display, stream));
2689
2690     if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR)
2691     {
2692         return EglBadState() << "Bad stream state";
2693     }
2694
2695     return ValidateStreamAttribute(attribute, value, display->getExtensions());
2696 }
2697
2698 Error ValidateQueryStreamKHR(const Display *display,
2699                              const Stream *stream,
2700                              EGLenum attribute,
2701                              EGLint *value)
2702 {
2703     ANGLE_TRY(ValidateStream(display, stream));
2704
2705     switch (attribute)
2706     {
2707         case EGL_STREAM_STATE_KHR:
2708         case EGL_CONSUMER_LATENCY_USEC_KHR:
2709             break;
2710         case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR:
2711             if (!display->getExtensions().streamConsumerGLTexture)
2712             {
2713                 return EglBadAttribute() << "Consumer GLTexture extension not active";
2714             }
2715             break;
2716         default:
2717             return EglBadAttribute() << "Invalid attribute";
2718     }
2719
2720     return NoError();
2721 }
2722
2723 Error ValidateQueryStreamu64KHR(const Display *display,
2724                                 const Stream *stream,
2725                                 EGLenum attribute,
2726                                 EGLuint64KHR *value)
2727 {
2728     ANGLE_TRY(ValidateStream(display, stream));
2729
2730     switch (attribute)
2731     {
2732         case EGL_CONSUMER_FRAME_KHR:
2733         case EGL_PRODUCER_FRAME_KHR:
2734             break;
2735         default:
2736             return EglBadAttribute() << "Invalid attribute";
2737     }
2738
2739     return NoError();
2740 }
2741
2742 Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display,
2743                                                  gl::Context *context,
2744                                                  const Stream *stream)
2745 {
2746     ANGLE_TRY(ValidateContext(display, context));
2747
2748     const DisplayExtensions &displayExtensions = display->getExtensions();
2749     if (!displayExtensions.streamConsumerGLTexture)
2750     {
2751         return EglBadAccess() << "Stream consumer extension not active";
2752     }
2753
2754     if (!context->getExtensions().eglStreamConsumerExternalNV)
2755     {
2756         return EglBadAccess() << "EGL stream consumer external GL extension not enabled";
2757     }
2758
2759     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
2760     {
2761         return EglBadStream() << "Invalid stream";
2762     }
2763
2764     if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR)
2765     {
2766         return EglBadState() << "Invalid stream state";
2767     }
2768
2769     // Lookup the texture and ensure it is correct
2770     gl::Texture *texture = context->getState().getTargetTexture(gl::TextureType::External);
2771     if (texture == nullptr || texture->id().value == 0)
2772     {
2773         return EglBadAccess() << "No external texture bound";
2774     }
2775
2776     return NoError();
2777 }
2778
2779 Error ValidateStreamConsumerAcquireKHR(const Display *display,
2780                                        gl::Context *context,
2781                                        const Stream *stream)
2782 {
2783     ANGLE_TRY(ValidateDisplay(display));
2784
2785     const DisplayExtensions &displayExtensions = display->getExtensions();
2786     if (!displayExtensions.streamConsumerGLTexture)
2787     {
2788         return EglBadAccess() << "Stream consumer extension not active";
2789     }
2790
2791     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
2792     {
2793         return EglBadStream() << "Invalid stream";
2794     }
2795
2796     if (!context)
2797     {
2798         return EglBadAccess() << "No GL context current to calling thread.";
2799     }
2800
2801     ANGLE_TRY(ValidateContext(display, context));
2802
2803     if (!stream->isConsumerBoundToContext(context))
2804     {
2805         return EglBadAccess() << "Current GL context not associated with stream consumer";
2806     }
2807
2808     if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB &&
2809         stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV)
2810     {
2811         return EglBadAccess() << "Invalid stream consumer type";
2812     }
2813
2814     // Note: technically EGL_STREAM_STATE_EMPTY_KHR is a valid state when the timeout is non-zero.
2815     // However, the timeout is effectively ignored since it has no useful functionality with the
2816     // current producers that are implemented, so we don't allow that state
2817     if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
2818         stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
2819     {
2820         return EglBadState() << "Invalid stream state";
2821     }
2822
2823     return NoError();
2824 }
2825
2826 Error ValidateStreamConsumerReleaseKHR(const Display *display,
2827                                        gl::Context *context,
2828                                        const Stream *stream)
2829 {
2830     ANGLE_TRY(ValidateDisplay(display));
2831
2832     const DisplayExtensions &displayExtensions = display->getExtensions();
2833     if (!displayExtensions.streamConsumerGLTexture)
2834     {
2835         return EglBadAccess() << "Stream consumer extension not active";
2836     }
2837
2838     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
2839     {
2840         return EglBadStream() << "Invalid stream";
2841     }
2842
2843     if (!context)
2844     {
2845         return EglBadAccess() << "No GL context current to calling thread.";
2846     }
2847
2848     ANGLE_TRY(ValidateContext(display, context));
2849
2850     if (!stream->isConsumerBoundToContext(context))
2851     {
2852         return EglBadAccess() << "Current GL context not associated with stream consumer";
2853     }
2854
2855     if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB &&
2856         stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV)
2857     {
2858         return EglBadAccess() << "Invalid stream consumer type";
2859     }
2860
2861     if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
2862         stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
2863     {
2864         return EglBadState() << "Invalid stream state";
2865     }
2866
2867     return NoError();
2868 }
2869
2870 Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display,
2871                                                        gl::Context *context,
2872                                                        const Stream *stream,
2873                                                        const AttributeMap &attribs)
2874 {
2875     ANGLE_TRY(ValidateDisplay(display));
2876
2877     const DisplayExtensions &displayExtensions = display->getExtensions();
2878     if (!displayExtensions.streamConsumerGLTexture)
2879     {
2880         return EglBadAccess() << "Stream consumer extension not active";
2881     }
2882
2883     ANGLE_TRY(ValidateContext(display, context));
2884
2885     // Although technically not a requirement in spec, the context needs to be checked for support
2886     // for external textures or future logic will cause assertations. This extension is also
2887     // effectively useless without external textures.
2888     if (!context->getExtensions().eglStreamConsumerExternalNV)
2889     {
2890         return EglBadAccess() << "EGL stream consumer external GL extension not enabled";
2891     }
2892
2893     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
2894     {
2895         return EglBadStream() << "Invalid stream";
2896     }
2897
2898     if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR)
2899     {
2900         return EglBadState() << "Invalid stream state";
2901     }
2902
2903     const gl::Caps &glCaps = context->getCaps();
2904
2905     EGLAttrib colorBufferType = EGL_RGB_BUFFER;
2906     EGLAttrib planeCount      = -1;
2907     EGLAttrib plane[3];
2908     for (int i = 0; i < 3; i++)
2909     {
2910         plane[i] = -1;
2911     }
2912     for (const auto &attributeIter : attribs)
2913     {
2914         EGLAttrib attribute = attributeIter.first;
2915         EGLAttrib value     = attributeIter.second;
2916
2917         switch (attribute)
2918         {
2919             case EGL_COLOR_BUFFER_TYPE:
2920                 if (value != EGL_RGB_BUFFER && value != EGL_YUV_BUFFER_EXT)
2921                 {
2922                     return EglBadParameter() << "Invalid color buffer type";
2923                 }
2924                 colorBufferType = value;
2925                 break;
2926             case EGL_YUV_NUMBER_OF_PLANES_EXT:
2927                 // planeCount = -1 is a tag for the default plane count so the value must be checked
2928                 // to be positive here to ensure future logic doesn't break on invalid negative
2929                 // inputs
2930                 if (value < 0)
2931                 {
2932                     return EglBadMatch() << "Invalid plane count";
2933                 }
2934                 planeCount = value;
2935                 break;
2936             default:
2937                 if (attribute >= EGL_YUV_PLANE0_TEXTURE_UNIT_NV &&
2938                     attribute <= EGL_YUV_PLANE2_TEXTURE_UNIT_NV)
2939                 {
2940                     if ((value < 0 ||
2941                          value >= static_cast<EGLAttrib>(glCaps.maxCombinedTextureImageUnits)) &&
2942                         value != EGL_NONE)
2943                     {
2944                         return EglBadAccess() << "Invalid texture unit";
2945                     }
2946                     plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value;
2947                 }
2948                 else
2949                 {
2950                     return EglBadAttribute() << "Invalid attribute";
2951                 }
2952         }
2953     }
2954
2955     if (colorBufferType == EGL_RGB_BUFFER)
2956     {
2957         if (planeCount > 0)
2958         {
2959             return EglBadMatch() << "Plane count must be 0 for RGB buffer";
2960         }
2961         for (int i = 0; i < 3; i++)
2962         {
2963             if (plane[i] != -1)
2964             {
2965                 return EglBadMatch() << "Planes cannot be specified";
2966             }
2967         }
2968
2969         // Lookup the texture and ensure it is correct
2970         gl::Texture *texture = context->getState().getTargetTexture(gl::TextureType::External);
2971         if (texture == nullptr || texture->id().value == 0)
2972         {
2973             return EglBadAccess() << "No external texture bound";
2974         }
2975     }
2976     else
2977     {
2978         if (planeCount == -1)
2979         {
2980             planeCount = 2;
2981         }
2982         if (planeCount < 1 || planeCount > 3)
2983         {
2984             return EglBadMatch() << "Invalid YUV plane count";
2985         }
2986         for (EGLAttrib i = planeCount; i < 3; i++)
2987         {
2988             if (plane[i] != -1)
2989             {
2990                 return EglBadMatch() << "Invalid plane specified";
2991             }
2992         }
2993
2994         // Set to ensure no texture is referenced more than once
2995         std::set<gl::Texture *> textureSet;
2996         for (EGLAttrib i = 0; i < planeCount; i++)
2997         {
2998             if (plane[i] == -1)
2999             {
3000                 return EglBadMatch() << "Not all planes specified";
3001             }
3002             if (plane[i] != EGL_NONE)
3003             {
3004                 gl::Texture *texture = context->getState().getSamplerTexture(
3005                     static_cast<unsigned int>(plane[i]), gl::TextureType::External);
3006                 if (texture == nullptr || texture->id().value == 0)
3007                 {
3008                     return EglBadAccess()
3009                            << "No external texture bound at one or more specified texture units";
3010                 }
3011                 if (textureSet.find(texture) != textureSet.end())
3012                 {
3013                     return EglBadAccess() << "Multiple planes bound to same texture object";
3014                 }
3015                 textureSet.insert(texture);
3016             }
3017         }
3018     }
3019
3020     return NoError();
3021 }
3022
3023 Error ValidateCreateStreamProducerD3DTextureANGLE(const Display *display,
3024                                                   const Stream *stream,
3025                                                   const AttributeMap &attribs)
3026 {
3027     ANGLE_TRY(ValidateDisplay(display));
3028
3029     const DisplayExtensions &displayExtensions = display->getExtensions();
3030     if (!displayExtensions.streamProducerD3DTexture)
3031     {
3032         return EglBadAccess() << "Stream producer extension not active";
3033     }
3034
3035     ANGLE_TRY(ValidateStream(display, stream));
3036
3037     if (!attribs.isEmpty())
3038     {
3039         return EglBadAttribute() << "Invalid attribute";
3040     }
3041
3042     if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR)
3043     {
3044         return EglBadState() << "Stream not in connecting state";
3045     }
3046
3047     switch (stream->getConsumerType())
3048     {
3049         case Stream::ConsumerType::GLTextureYUV:
3050             if (stream->getPlaneCount() != 2)
3051             {
3052                 return EglBadMatch() << "Incompatible stream consumer type";
3053             }
3054             break;
3055
3056         case Stream::ConsumerType::GLTextureRGB:
3057             if (stream->getPlaneCount() != 1)
3058             {
3059                 return EglBadMatch() << "Incompatible stream consumer type";
3060             }
3061             break;
3062
3063         default:
3064             return&n