1 //
2 // Copyright (c) 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/Image.h"
17 #include "libANGLE/Stream.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/Texture.h"
20 #include "libANGLE/formatutils.h"
21 
22 #include <EGL/eglext.h>
23 
24 namespace egl
25 {
26 namespace
27 {
GetMaximumMipLevel(const gl::Context * context,GLenum target)28 size_t GetMaximumMipLevel(const gl::Context *context, GLenum target)
29 {
30     const gl::Caps &caps = context->getCaps();
31 
32     size_t maxDimension = 0;
33     switch (target)
34     {
35         case GL_TEXTURE_2D:
36             maxDimension = caps.max2DTextureSize;
37             break;
38         case GL_TEXTURE_RECTANGLE_ANGLE:
39             maxDimension = caps.maxRectangleTextureSize;
40             break;
41         case GL_TEXTURE_CUBE_MAP:
42             maxDimension = caps.maxCubeMapTextureSize;
43             break;
44         case GL_TEXTURE_3D:
45             maxDimension = caps.max3DTextureSize;
46             break;
47         case GL_TEXTURE_2D_ARRAY:
48             maxDimension = caps.max2DTextureSize;
49             break;
50         default:
51             UNREACHABLE();
52     }
53 
54     return gl::log2(static_cast<int>(maxDimension));
55 }
56 
TextureHasNonZeroMipLevelsSpecified(const gl::Context * context,const gl::Texture * texture)57 bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::Texture *texture)
58 {
59     size_t maxMip = GetMaximumMipLevel(context, texture->getTarget());
60     for (size_t level = 1; level < maxMip; level++)
61     {
62         if (texture->getTarget() == GL_TEXTURE_CUBE_MAP)
63         {
64             for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget;
65                  face++)
66             {
67                 if (texture->getFormat(face, level).valid())
68                 {
69                     return true;
70                 }
71             }
72         }
73         else
74         {
75             if (texture->getFormat(texture->getTarget(), level).valid())
76             {
77                 return true;
78             }
79         }
80     }
81 
82     return false;
83 }
84 
CubeTextureHasUnspecifiedLevel0Face(const gl::Texture * texture)85 bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture)
86 {
87     ASSERT(texture->getTarget() == GL_TEXTURE_CUBE_MAP);
88     for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++)
89     {
90         if (!texture->getFormat(face, 0).valid())
91         {
92             return true;
93         }
94     }
95 
96     return false;
97 }
98 
ValidateStreamAttribute(const EGLAttrib attribute,const EGLAttrib value,const DisplayExtensions & extensions)99 Error ValidateStreamAttribute(const EGLAttrib attribute,
100                               const EGLAttrib value,
101                               const DisplayExtensions &extensions)
102 {
103     switch (attribute)
104     {
105         case EGL_STREAM_STATE_KHR:
106         case EGL_PRODUCER_FRAME_KHR:
107         case EGL_CONSUMER_FRAME_KHR:
108             return EglBadAccess() << "Attempt to initialize readonly parameter";
109         case EGL_CONSUMER_LATENCY_USEC_KHR:
110             // Technically not in spec but a latency < 0 makes no sense so we check it
111             if (value < 0)
112             {
113                 return EglBadParameter() << "Latency must be positive";
114             }
115             break;
116         case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR:
117             if (!extensions.streamConsumerGLTexture)
118             {
119                 return EglBadAttribute() << "Consumer GL extension not enabled";
120             }
121             // Again not in spec but it should be positive anyways
122             if (value < 0)
123             {
124                 return EglBadParameter() << "Timeout must be positive";
125             }
126             break;
127         default:
128             return EglBadAttribute() << "Invalid stream attribute";
129     }
130     return NoError();
131 }
132 
ValidateCreateImageKHRMipLevelCommon(gl::Context * context,const gl::Texture * texture,EGLAttrib level)133 Error ValidateCreateImageKHRMipLevelCommon(gl::Context *context,
134                                            const gl::Texture *texture,
135                                            EGLAttrib level)
136 {
137     // Note that the spec EGL_KHR_create_image spec does not explicitly specify an error
138     // when the level is outside the base/max level range, but it does mention that the
139     // level "must be a part of the complete texture object <buffer>". It can be argued
140     // that out-of-range levels are not a part of the complete texture.
141     const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
142     if (level > 0 &&
143         (!texture->isMipmapComplete() || static_cast<GLuint>(level) < effectiveBaseLevel ||
144          static_cast<GLuint>(level) > texture->getTextureState().getMipmapMaxLevel()))
145     {
146         return EglBadParameter() << "texture must be complete if level is non-zero.";
147     }
148 
149     if (level == 0 && !texture->isMipmapComplete() &&
150         TextureHasNonZeroMipLevelsSpecified(context, texture))
151     {
152         return EglBadParameter() << "if level is zero and the texture is incomplete, it must "
153                                     "have no mip levels specified except zero.";
154     }
155 
156     return NoError();
157 }
158 
ValidateConfigAttribute(const Display * display,EGLAttrib attribute)159 Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute)
160 {
161     switch (attribute)
162     {
163         case EGL_BUFFER_SIZE:
164         case EGL_ALPHA_SIZE:
165         case EGL_BLUE_SIZE:
166         case EGL_GREEN_SIZE:
167         case EGL_RED_SIZE:
168         case EGL_DEPTH_SIZE:
169         case EGL_STENCIL_SIZE:
170         case EGL_CONFIG_CAVEAT:
171         case EGL_CONFIG_ID:
172         case EGL_LEVEL:
173         case EGL_NATIVE_RENDERABLE:
174         case EGL_NATIVE_VISUAL_ID:
175         case EGL_NATIVE_VISUAL_TYPE:
176         case EGL_SAMPLES:
177         case EGL_SAMPLE_BUFFERS:
178         case EGL_SURFACE_TYPE:
179         case EGL_TRANSPARENT_TYPE:
180         case EGL_TRANSPARENT_BLUE_VALUE:
181         case EGL_TRANSPARENT_GREEN_VALUE:
182         case EGL_TRANSPARENT_RED_VALUE:
183         case EGL_BIND_TO_TEXTURE_RGB:
184         case EGL_BIND_TO_TEXTURE_RGBA:
185         case EGL_MIN_SWAP_INTERVAL:
186         case EGL_MAX_SWAP_INTERVAL:
187         case EGL_LUMINANCE_SIZE:
188         case EGL_ALPHA_MASK_SIZE:
189         case EGL_COLOR_BUFFER_TYPE:
190         case EGL_RENDERABLE_TYPE:
191         case EGL_MATCH_NATIVE_PIXMAP:
192         case EGL_CONFORMANT:
193         case EGL_MAX_PBUFFER_WIDTH:
194         case EGL_MAX_PBUFFER_HEIGHT:
195         case EGL_MAX_PBUFFER_PIXELS:
196             break;
197 
198         case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
199             if (!display->getExtensions().surfaceOrientation)
200             {
201                 return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled.";
202             }
203             break;
204 
205         case EGL_COLOR_COMPONENT_TYPE_EXT:
206             if (!display->getExtensions().pixelFormatFloat)
207             {
208                 return EglBadAttribute() << "EGL_EXT_pixel_format_float is not enabled.";
209             }
210             break;
211 
212         default:
213             return EglBadAttribute() << "Unknown attribute.";
214     }
215 
216     return NoError();
217 }
218 
ValidateConfigAttributes(const Display * display,const AttributeMap & attributes)219 Error ValidateConfigAttributes(const Display *display, const AttributeMap &attributes)
220 {
221     for (const auto &attrib : attributes)
222     {
223         ANGLE_TRY(ValidateConfigAttribute(display, attrib.first));
224     }
225 
226     return NoError();
227 }
228 
ValidatePlatformType(const ClientExtensions & clientExtensions,EGLAttrib platformType)229 Error ValidatePlatformType(const ClientExtensions &clientExtensions, EGLAttrib platformType)
230 {
231     switch (platformType)
232     {
233         case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
234             break;
235 
236         case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
237         case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
238             if (!clientExtensions.platformANGLED3D)
239             {
240                 return EglBadAttribute() << "Direct3D platform is unsupported.";
241             }
242             break;
243 
244         case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
245         case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
246             if (!clientExtensions.platformANGLEOpenGL)
247             {
248                 return EglBadAttribute() << "OpenGL platform is unsupported.";
249             }
250             break;
251 
252         case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
253             if (!clientExtensions.platformANGLENULL)
254             {
255                 return EglBadAttribute() << "Display type EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE "
256                                             "requires EGL_ANGLE_platform_angle_null.";
257             }
258             break;
259 
260         case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
261             if (!clientExtensions.platformANGLEVulkan)
262             {
263                 return EglBadAttribute() << "Vulkan platform is unsupported.";
264             }
265             break;
266 
267         default:
268             return EglBadAttribute() << "Unknown platform type.";
269     }
270 
271     return NoError();
272 }
273 
ValidateGetPlatformDisplayCommon(EGLenum platform,void * native_display,const AttributeMap & attribMap)274 Error ValidateGetPlatformDisplayCommon(EGLenum platform,
275                                        void *native_display,
276                                        const AttributeMap &attribMap)
277 {
278     const ClientExtensions &clientExtensions = Display::GetClientExtensions();
279 
280     switch (platform)
281     {
282         case EGL_PLATFORM_ANGLE_ANGLE:
283             if (!clientExtensions.platformANGLE)
284             {
285                 return EglBadParameter() << "Platform ANGLE extension is not active";
286             }
287             break;
288         case EGL_PLATFORM_DEVICE_EXT:
289             if (!clientExtensions.platformDevice)
290             {
291                 return EglBadParameter() << "Platform Device extension is not active";
292             }
293             break;
294         default:
295             return EglBadConfig() << "Bad platform type.";
296     }
297 
298     if (platform == EGL_PLATFORM_ANGLE_ANGLE)
299     {
300         EGLAttrib platformType       = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
301         EGLAttrib deviceType         = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
302         bool enableAutoTrimSpecified = false;
303         bool deviceTypeSpecified     = false;
304         bool presentPathSpecified    = false;
305 
306         Optional<EGLAttrib> majorVersion;
307         Optional<EGLAttrib> minorVersion;
308 
309         for (const auto &curAttrib : attribMap)
310         {
311             const EGLAttrib value = curAttrib.second;
312 
313             switch (curAttrib.first)
314             {
315                 case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
316                 {
317                     ANGLE_TRY(ValidatePlatformType(clientExtensions, value));
318                     platformType = value;
319                     break;
320                 }
321 
322                 case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
323                     if (value != EGL_DONT_CARE)
324                     {
325                         majorVersion = value;
326                     }
327                     break;
328 
329                 case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
330                     if (value != EGL_DONT_CARE)
331                     {
332                         minorVersion = value;
333                     }
334                     break;
335 
336                 case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
337                     switch (value)
338                     {
339                         case EGL_TRUE:
340                         case EGL_FALSE:
341                             break;
342                         default:
343                             return EglBadAttribute() << "Invalid automatic trim attribute";
344                     }
345                     enableAutoTrimSpecified = true;
346                     break;
347 
348                 case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE:
349                     if (!clientExtensions.experimentalPresentPath)
350                     {
351                         return EglBadAttribute()
352                                << "EGL_ANGLE_experimental_present_path extension not active";
353                     }
354 
355                     switch (value)
356                     {
357                         case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE:
358                         case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE:
359                             break;
360                         default:
361                             return EglBadAttribute()
362                                    << "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE";
363                     }
364                     presentPathSpecified = true;
365                     break;
366 
367                 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
368                     switch (value)
369                     {
370                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
371                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
372                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
373                             deviceTypeSpecified = true;
374                             break;
375 
376                         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
377                             // This is a hidden option, accepted by the OpenGL back-end.
378                             break;
379 
380                         default:
381                             return EglBadAttribute() << "Invalid value for "
382                                                         "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE "
383                                                         "attrib";
384                     }
385                     deviceType = value;
386                     break;
387 
388                 case EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE:
389                     if (!clientExtensions.platformANGLE)
390                     {
391                         return EglBadAttribute() << "EGL_ANGLE_platform_angle extension not active";
392                     }
393                     if (value != EGL_TRUE && value != EGL_FALSE && value != EGL_DONT_CARE)
394                     {
395                         return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE "
396                                                     "must be EGL_TRUE, EGL_FALSE, or "
397                                                     "EGL_DONT_CARE.";
398                     }
399                     break;
400 
401                 default:
402                     break;
403             }
404         }
405 
406         if (!majorVersion.valid() && minorVersion.valid())
407         {
408             return EglBadAttribute()
409                    << "Must specify major version if you specify a minor version.";
410         }
411 
412         if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
413             platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
414         {
415             return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a "
416                                         "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
417         }
418 
419         if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
420         {
421             return EglBadAttribute() << "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE "
422                                         "requires a device type of "
423                                         "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
424         }
425 
426         if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
427         {
428             return EglBadAttribute() << "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a "
429                                         "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.";
430         }
431 
432         if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
433             platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
434         {
435             return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a "
436                                         "device type of EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or "
437                                         "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE.";
438         }
439 
440         if (platformType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
441         {
442             if ((majorVersion.valid() && majorVersion.value() != 1) ||
443                 (minorVersion.valid() && minorVersion.value() != 0))
444             {
445                 return EglBadAttribute() << "EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE currently "
446                                             "only supports Vulkan 1.0.";
447             }
448         }
449     }
450     else if (platform == EGL_PLATFORM_DEVICE_EXT)
451     {
452         Device *eglDevice = reinterpret_cast<Device *>(native_display);
453         if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice))
454         {
455             return EglBadAttribute() << "native_display should be a valid EGL device if "
456                                         "platform equals EGL_PLATFORM_DEVICE_EXT";
457         }
458     }
459     else
460     {
461         UNREACHABLE();
462     }
463 
464     return NoError();
465 }
466 
467 }  // namespace
468 
ValidateDisplay(const Display * display)469 Error ValidateDisplay(const Display *display)
470 {
471     if (display == EGL_NO_DISPLAY)
472     {
473         return EglBadDisplay() << "display is EGL_NO_DISPLAY.";
474     }
475 
476     if (!Display::isValidDisplay(display))
477     {
478         return EglBadDisplay() << "display is not a valid display.";
479     }
480 
481     if (!display->isInitialized())
482     {
483         return EglNotInitialized() << "display is not initialized.";
484     }
485 
486     if (display->isDeviceLost())
487     {
488         return EglContextLost() << "display had a context loss";
489     }
490 
491     return NoError();
492 }
493 
ValidateSurface(const Display * display,const Surface * surface)494 Error ValidateSurface(const Display *display, const Surface *surface)
495 {
496     ANGLE_TRY(ValidateDisplay(display));
497 
498     if (!display->isValidSurface(surface))
499     {
500         return EglBadSurface();
501     }
502 
503     return NoError();
504 }
505 
ValidateConfig(const Display * display,const Config * config)506 Error ValidateConfig(const Display *display, const Config *config)
507 {
508     ANGLE_TRY(ValidateDisplay(display));
509 
510     if (!display->isValidConfig(config))
511     {
512         return EglBadConfig();
513     }
514 
515     return NoError();
516 }
517 
ValidateContext(const Display * display,const gl::Context * context)518 Error ValidateContext(const Display *display, const gl::Context *context)
519 {
520     ANGLE_TRY(ValidateDisplay(display));
521 
522     if (!display->isValidContext(context))
523     {
524         return EglBadContext();
525     }
526 
527     return NoError();
528 }
529 
ValidateImage(const Display * display,const Image * image)530 Error ValidateImage(const Display *display, const Image *image)
531 {
532     ANGLE_TRY(ValidateDisplay(display));
533 
534     if (!display->isValidImage(image))
535     {
536         return EglBadParameter() << "image is not valid.";
537     }
538 
539     return NoError();
540 }
541 
ValidateStream(const Display * display,const Stream * stream)542 Error ValidateStream(const Display *display, const Stream *stream)
543 {
544     ANGLE_TRY(ValidateDisplay(display));
545 
546     const DisplayExtensions &displayExtensions = display->getExtensions();
547     if (!displayExtensions.stream)
548     {
549         return EglBadAccess() << "Stream extension not active";
550     }
551 
552     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
553     {
554         return EglBadStream() << "Invalid stream";
555     }
556 
557     return NoError();
558 }
559 
ValidateCreateContext(Display * display,Config * configuration,gl::Context * shareContext,const AttributeMap & attributes)560 Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext,
561                             const AttributeMap& attributes)
562 {
563     ANGLE_TRY(ValidateConfig(display, configuration));
564 
565     // Get the requested client version (default is 1) and check it is 2 or 3.
566     EGLAttrib clientMajorVersion = 1;
567     EGLAttrib clientMinorVersion = 0;
568     EGLAttrib contextFlags       = 0;
569     bool resetNotification = false;
570     for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++)
571     {
572         EGLAttrib attribute = attributeIter->first;
573         EGLAttrib value     = attributeIter->second;
574 
575         switch (attribute)
576         {
577           case EGL_CONTEXT_CLIENT_VERSION:
578             clientMajorVersion = value;
579             break;
580 
581           case EGL_CONTEXT_MINOR_VERSION:
582             clientMinorVersion = value;
583             break;
584 
585           case EGL_CONTEXT_FLAGS_KHR:
586             contextFlags = value;
587             break;
588 
589           case EGL_CONTEXT_OPENGL_DEBUG:
590               break;
591 
592           case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
593             // Only valid for OpenGL (non-ES) contexts
594             return EglBadAttribute();
595 
596           case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
597             if (!display->getExtensions().createContextRobustness)
598             {
599                 return EglBadAttribute();
600             }
601             if (value != EGL_TRUE && value != EGL_FALSE)
602             {
603                 return EglBadAttribute();
604             }
605             break;
606 
607           case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
608             return EglBadAttribute() << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR is not"
609                                      << " valid for GLES with EGL 1.4 and KHR_create_context. Use"
610                                      << " EXT_create_context_robustness.";
611           case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
612             if (!display->getExtensions().createContextRobustness)
613             {
614                 return EglBadAttribute();
615             }
616             if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT)
617             {
618                 resetNotification = true;
619             }
620             else if (value != EGL_NO_RESET_NOTIFICATION_EXT)
621             {
622                 return EglBadAttribute();
623             }
624             break;
625 
626           case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
627               if (!display->getExtensions().createContextNoError)
628               {
629                   return EglBadAttribute() << "Invalid Context attribute.";
630               }
631               if (value != EGL_TRUE && value != EGL_FALSE)
632               {
633                   return EglBadAttribute() << "Attribute must be EGL_TRUE or EGL_FALSE.";
634               }
635               break;
636 
637           case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE:
638               if (!display->getExtensions().createContextWebGLCompatibility)
639               {
640                   return EglBadAttribute() << "Attribute "
641                                               "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires "
642                                               "EGL_ANGLE_create_context_webgl_compatibility.";
643               }
644               if (value != EGL_TRUE && value != EGL_FALSE)
645               {
646                   return EglBadAttribute()
647                          << "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be EGL_TRUE or EGL_FALSE.";
648               }
649               break;
650 
651           case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM:
652               if (!display->getExtensions().createContextBindGeneratesResource)
653               {
654                   return EglBadAttribute()
655                          << "Attribute EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM requires "
656                             "EGL_CHROMIUM_create_context_bind_generates_resource.";
657               }
658               if (value != EGL_TRUE && value != EGL_FALSE)
659               {
660                   return EglBadAttribute() << "EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM "
661                                               "must be EGL_TRUE or EGL_FALSE.";
662               }
663               break;
664 
665           case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE:
666               if (!display->getExtensions().displayTextureShareGroup)
667               {
668                   return EglBadAttribute() << "Attribute "
669                                               "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE requires "
670                                               "EGL_ANGLE_display_texture_share_group.";
671               }
672               if (value != EGL_TRUE && value != EGL_FALSE)
673               {
674                   return EglBadAttribute()
675                          << "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE must be EGL_TRUE or EGL_FALSE.";
676               }
677               if (shareContext &&
678                   (shareContext->usingDisplayTextureShareGroup() != (value == EGL_TRUE)))
679               {
680                   return EglBadAttribute() << "All contexts within a share group must be "
681                                               "created with the same value of "
682                                               "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE.";
683               }
684               break;
685 
686           case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE:
687               if (!display->getExtensions().createContextClientArrays)
688               {
689                   return EglBadAttribute()
690                          << "Attribute EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE requires "
691                             "EGL_ANGLE_create_context_client_arrays.";
692               }
693               if (value != EGL_TRUE && value != EGL_FALSE)
694               {
695                   return EglBadAttribute() << "EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE must "
696                                               "be EGL_TRUE or EGL_FALSE.";
697               }
698               break;
699 
700           case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE:
701               if (!display->getExtensions().programCacheControl)
702               {
703                   return EglBadAttribute()
704                          << "Attribute EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE "
705                             "requires EGL_ANGLE_program_cache_control.";
706               }
707               if (value != EGL_TRUE && value != EGL_FALSE)
708               {
709                   return EglBadAttribute() << "EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE must "
710                                               "be EGL_TRUE or EGL_FALSE.";
711               }
712               break;
713 
714           case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
715               if (!display->getExtensions().robustResourceInitialization)
716               {
717                   return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
718                                               "requires EGL_ANGLE_robust_resource_initialization.";
719               }
720               if (value != EGL_TRUE && value != EGL_FALSE)
721               {
722                   return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
723                                               "either EGL_TRUE or EGL_FALSE.";
724               }
725               break;
726 
727           default:
728               return EglBadAttribute() << "Unknown attribute.";
729         }
730     }
731 
732     switch (clientMajorVersion)
733     {
734         case 2:
735             if (clientMinorVersion != 0)
736             {
737                 return EglBadConfig();
738             }
739             break;
740         case 3:
741             if (clientMinorVersion != 0 && clientMinorVersion != 1)
742             {
743                 return EglBadConfig();
744             }
745             if (!(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR))
746             {
747                 return EglBadConfig();
748             }
749             if (display->getMaxSupportedESVersion() <
750                 gl::Version(static_cast<GLuint>(clientMajorVersion),
751                             static_cast<GLuint>(clientMinorVersion)))
752             {
753                 return EglBadConfig() << "Requested GLES version is not supported.";
754             }
755             break;
756         default:
757             return EglBadConfig();
758             break;
759     }
760 
761     // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES
762     const EGLint validContextFlags = (EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR |
763                                       EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
764     if ((contextFlags & ~validContextFlags) != 0)
765     {
766         return EglBadAttribute();
767     }
768 
769     if (shareContext)
770     {
771         // Shared context is invalid or is owned by another display
772         if (!display->isValidContext(shareContext))
773         {
774             return EglBadMatch();
775         }
776 
777         if (shareContext->isResetNotificationEnabled() != resetNotification)
778         {
779             return EglBadMatch();
780         }
781 
782         if (shareContext->getClientMajorVersion() != clientMajorVersion ||
783             shareContext->getClientMinorVersion() != clientMinorVersion)
784         {
785             return EglBadContext();
786         }
787     }
788 
789     return NoError();
790 }
791 
ValidateCreateWindowSurface(Display * display,Config * config,EGLNativeWindowType window,const AttributeMap & attributes)792 Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window,
793                                   const AttributeMap& attributes)
794 {
795     ANGLE_TRY(ValidateConfig(display, config));
796 
797     if (!display->isValidNativeWindow(window))
798     {
799         return EglBadNativeWindow();
800     }
801 
802     const DisplayExtensions &displayExtensions = display->getExtensions();
803 
804     for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++)
805     {
806         EGLAttrib attribute = attributeIter->first;
807         EGLAttrib value     = attributeIter->second;
808 
809         switch (attribute)
810         {
811           case EGL_RENDER_BUFFER:
812             switch (value)
813             {
814               case EGL_BACK_BUFFER:
815                 break;
816               case EGL_SINGLE_BUFFER:
817                   return EglBadMatch();  // Rendering directly to front buffer not supported
818               default:
819                   return EglBadAttribute();
820             }
821             break;
822 
823           case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
824             if (!displayExtensions.postSubBuffer)
825             {
826                 return EglBadAttribute();
827             }
828             break;
829 
830           case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
831               if (!displayExtensions.flexibleSurfaceCompatibility)
832               {
833                   return EglBadAttribute();
834               }
835               break;
836 
837           case EGL_WIDTH:
838           case EGL_HEIGHT:
839             if (!displayExtensions.windowFixedSize)
840             {
841                 return EglBadAttribute();
842             }
843             if (value < 0)
844             {
845                 return EglBadParameter();
846             }
847             break;
848 
849           case EGL_FIXED_SIZE_ANGLE:
850             if (!displayExtensions.windowFixedSize)
851             {
852                 return EglBadAttribute();
853             }
854             break;
855 
856           case EGL_SURFACE_ORIENTATION_ANGLE:
857               if (!displayExtensions.surfaceOrientation)
858               {
859                   return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled.";
860               }
861               break;
862 
863           case EGL_VG_COLORSPACE:
864               return EglBadMatch();
865 
866           case EGL_VG_ALPHA_FORMAT:
867               return EglBadMatch();
868 
869           case EGL_DIRECT_COMPOSITION_ANGLE:
870               if (!displayExtensions.directComposition)
871               {
872                   return EglBadAttribute();
873               }
874               break;
875 
876           case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
877               if (!display->getExtensions().robustResourceInitialization)
878               {
879                   return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
880                                               "requires EGL_ANGLE_robust_resource_initialization.";
881               }
882               if (value != EGL_TRUE && value != EGL_FALSE)
883               {
884                   return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
885                                               "either EGL_TRUE or EGL_FALSE.";
886               }
887               break;
888 
889           default:
890               return EglBadAttribute();
891         }
892     }
893 
894     if (Display::hasExistingWindowSurface(window))
895     {
896         return EglBadAlloc();
897     }
898 
899     return NoError();
900 }
901 
ValidateCreatePbufferSurface(Display * display,Config * config,const AttributeMap & attributes)902 Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes)
903 {
904     ANGLE_TRY(ValidateConfig(display, config));
905 
906     const DisplayExtensions &displayExtensions = display->getExtensions();
907 
908     for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++)
909     {
910         EGLAttrib attribute = attributeIter->first;
911         EGLAttrib value     = attributeIter->second;
912 
913         switch (attribute)
914         {
915           case EGL_WIDTH:
916           case EGL_HEIGHT:
917             if (value < 0)
918             {
919                 return EglBadParameter();
920             }
921             break;
922 
923           case EGL_LARGEST_PBUFFER:
924             break;
925 
926           case EGL_TEXTURE_FORMAT:
927             switch (value)
928             {
929               case EGL_NO_TEXTURE:
930               case EGL_TEXTURE_RGB:
931               case EGL_TEXTURE_RGBA:
932                 break;
933               default:
934                   return EglBadAttribute();
935             }
936             break;
937 
938           case EGL_TEXTURE_TARGET:
939             switch (value)
940             {
941               case EGL_NO_TEXTURE:
942               case EGL_TEXTURE_2D:
943                 break;
944               default:
945                   return EglBadAttribute();
946             }
947             break;
948 
949           case EGL_MIPMAP_TEXTURE:
950             break;
951 
952           case EGL_VG_COLORSPACE:
953             break;
954 
955           case EGL_VG_ALPHA_FORMAT:
956             break;
957 
958           case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
959               if (!displayExtensions.flexibleSurfaceCompatibility)
960               {
961                   return EglBadAttribute()
962                          << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used "
963                             "without EGL_ANGLE_flexible_surface_compatibility support.";
964               }
965               break;
966 
967           case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
968               if (!display->getExtensions().robustResourceInitialization)
969               {
970                   return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
971                                               "requires EGL_ANGLE_robust_resource_initialization.";
972               }
973               if (value != EGL_TRUE && value != EGL_FALSE)
974               {
975                   return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
976                                               "either EGL_TRUE or EGL_FALSE.";
977               }
978               break;
979 
980           default:
981               return EglBadAttribute();
982         }
983     }
984 
985     if (!(config->surfaceType & EGL_PBUFFER_BIT))
986     {
987         return EglBadMatch();
988     }
989 
990     const Caps &caps = display->getCaps();
991 
992     EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
993     EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
994 
995     if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
996         (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
997     {
998         return EglBadMatch();
999     }
1000 
1001     if ((textureFormat == EGL_TEXTURE_RGB  && config->bindToTextureRGB != EGL_TRUE) ||
1002         (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
1003     {
1004         return EglBadAttribute();
1005     }
1006 
1007     EGLint width  = static_cast<EGLint>(attributes.get(EGL_WIDTH, 0));
1008     EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, 0));
1009     if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height)))
1010     {
1011         return EglBadMatch();
1012     }
1013 
1014     return NoError();
1015 }
1016 
ValidateCreatePbufferFromClientBuffer(Display * display,EGLenum buftype,EGLClientBuffer buffer,Config * config,const AttributeMap & attributes)1017 Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer,
1018                                             Config *config, const AttributeMap& attributes)
1019 {
1020     ANGLE_TRY(ValidateConfig(display, config));
1021 
1022     const DisplayExtensions &displayExtensions = display->getExtensions();
1023 
1024     switch (buftype)
1025     {
1026       case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
1027         if (!displayExtensions.d3dShareHandleClientBuffer)
1028         {
1029             return EglBadParameter();
1030         }
1031         if (buffer == nullptr)
1032         {
1033             return EglBadParameter();
1034         }
1035         break;
1036 
1037       case EGL_D3D_TEXTURE_ANGLE:
1038           if (!displayExtensions.d3dTextureClientBuffer)
1039           {
1040               return EglBadParameter();
1041           }
1042           if (buffer == nullptr)
1043           {
1044               return EglBadParameter();
1045           }
1046           break;
1047 
1048       default:
1049           return EglBadParameter();
1050     }
1051 
1052     for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++)
1053     {
1054         EGLAttrib attribute = attributeIter->first;
1055         EGLAttrib value     = attributeIter->second;
1056 
1057         switch (attribute)
1058         {
1059           case EGL_WIDTH:
1060           case EGL_HEIGHT:
1061             if (!displayExtensions.d3dShareHandleClientBuffer)
1062             {
1063                 return EglBadParameter();
1064             }
1065             if (value < 0)
1066             {
1067                 return EglBadParameter();
1068             }
1069             break;
1070 
1071           case EGL_TEXTURE_FORMAT:
1072             switch (value)
1073             {
1074               case EGL_NO_TEXTURE:
1075               case EGL_TEXTURE_RGB:
1076               case EGL_TEXTURE_RGBA:
1077                 break;
1078               default:
1079                   return EglBadAttribute();
1080             }
1081             break;
1082 
1083           case EGL_TEXTURE_TARGET:
1084             switch (value)
1085             {
1086               case EGL_NO_TEXTURE:
1087               case EGL_TEXTURE_2D:
1088                 break;
1089               default:
1090                   return EglBadAttribute();
1091             }
1092             break;
1093 
1094           case EGL_MIPMAP_TEXTURE:
1095             break;
1096 
1097           case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
1098               if (!displayExtensions.flexibleSurfaceCompatibility)
1099               {
1100                   return EglBadAttribute()
1101                          << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used "
1102                             "without EGL_ANGLE_flexible_surface_compatibility support.";
1103               }
1104               break;
1105 
1106           default:
1107               return EglBadAttribute();
1108         }
1109     }
1110 
1111     if (!(config->surfaceType & EGL_PBUFFER_BIT))
1112     {
1113         return EglBadMatch();
1114     }
1115 
1116     EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
1117     EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
1118     if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
1119         (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
1120     {
1121         return EglBadMatch();
1122     }
1123 
1124     if ((textureFormat == EGL_TEXTURE_RGB  && config->bindToTextureRGB  != EGL_TRUE) ||
1125         (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
1126     {
1127         return EglBadAttribute();
1128     }
1129 
1130     if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
1131     {
1132         EGLint width  = static_cast<EGLint>(attributes.get(EGL_WIDTH, 0));
1133         EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, 0));
1134 
1135         if (width == 0 || height == 0)
1136         {
1137             return EglBadAttribute();
1138         }
1139 
1140         const Caps &caps = display->getCaps();
1141         if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height)))
1142         {
1143             return EglBadMatch();
1144         }
1145     }
1146 
1147     ANGLE_TRY(display->validateClientBuffer(config, buftype, buffer, attributes));
1148 
1149     return NoError();
1150 }
1151 
ValidateMakeCurrent(Display * display,EGLSurface draw,EGLSurface read,gl::Context * context)1152 Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context)
1153 {
1154     if (context == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
1155     {
1156         return EglBadMatch() << "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE";
1157     }
1158 
1159     // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH
1160     // error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE.
1161     if (context != EGL_NO_CONTEXT && (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE))
1162     {
1163         if (display->getExtensions().surfacelessContext)
1164         {
1165             if ((draw == EGL_NO_SURFACE) != (read == EGL_NO_SURFACE))
1166             {
1167                 return EglBadMatch() << "If ctx is not EGL_NOT_CONTEXT, draw or read must "
1168                                         "both be EGL_NO_SURFACE, or both not";
1169             }
1170         }
1171         else
1172         {
1173             return EglBadMatch()
1174                    << "If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE";
1175         }
1176     }
1177 
1178     // If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an
1179     // EGL_BAD_MATCH error is generated.
1180     if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE))
1181     {
1182         return EglBadMatch()
1183                << "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE";
1184     }
1185 
1186     if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
1187     {
1188         return EglBadDisplay() << "'dpy' not a valid EGLDisplay handle";
1189     }
1190 
1191     // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null
1192     if (!display->isInitialized() &&
1193         (context != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE))
1194     {
1195         return EglNotInitialized() << "'dpy' not initialized";
1196     }
1197 
1198     if (context != EGL_NO_CONTEXT)
1199     {
1200         ANGLE_TRY(ValidateContext(display, context));
1201     }
1202 
1203     if (display->isInitialized() && display->testDeviceLost())
1204     {
1205         return EglContextLost();
1206     }
1207 
1208     Surface *drawSurface = static_cast<Surface *>(draw);
1209     if (draw != EGL_NO_SURFACE)
1210     {
1211         ANGLE_TRY(ValidateSurface(display, drawSurface));
1212     }
1213 
1214     Surface *readSurface = static_cast<Surface *>(read);
1215     if (read != EGL_NO_SURFACE)
1216     {
1217         ANGLE_TRY(ValidateSurface(display, readSurface));
1218     }
1219 
1220     if (readSurface)
1221     {
1222         ANGLE_TRY(ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface,
1223                                             context->getConfig(), readSurface->getType()));
1224     }
1225 
1226     if (draw != read)
1227     {
1228         UNIMPLEMENTED();  // FIXME
1229 
1230         if (drawSurface)
1231         {
1232             ANGLE_TRY(ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface,
1233                                                 context->getConfig(), drawSurface->getType()));
1234         }
1235     }
1236     return NoError();
1237 }
1238 
ValidateCompatibleConfigs(const Display * display,const Config * config1,const Surface * surface,const Config * config2,EGLint surfaceType)1239 Error ValidateCompatibleConfigs(const Display *display,
1240                                 const Config *config1,
1241                                 const Surface *surface,
1242                                 const Config *config2,
1243                                 EGLint surfaceType)
1244 {
1245 
1246     if (!surface->flexibleSurfaceCompatibilityRequested())
1247     {
1248         // Config compatibility is defined in section 2.2 of the EGL 1.5 spec
1249 
1250         bool colorBufferCompat = config1->colorBufferType == config2->colorBufferType;
1251         if (!colorBufferCompat)
1252         {
1253             return EglBadMatch() << "Color buffer types are not compatible.";
1254         }
1255 
1256         bool colorCompat =
1257             config1->redSize == config2->redSize && config1->greenSize == config2->greenSize &&
1258             config1->blueSize == config2->blueSize && config1->alphaSize == config2->alphaSize &&
1259             config1->luminanceSize == config2->luminanceSize;
1260         if (!colorCompat)
1261         {
1262             return EglBadMatch() << "Color buffer sizes are not compatible.";
1263         }
1264 
1265         bool componentTypeCompat = config1->colorComponentType == config2->colorComponentType;
1266         if (!componentTypeCompat)
1267         {
1268             return EglBadMatch() << "Color buffer component types are not compatible.";
1269         }
1270 
1271         bool dsCompat = config1->depthSize == config2->depthSize &&
1272                         config1->stencilSize == config2->stencilSize;
1273         if (!dsCompat)
1274         {
1275             return EglBadMatch() << "Depth-stencil buffer types are not compatible.";
1276         }
1277     }
1278 
1279     bool surfaceTypeCompat = (config1->surfaceType & config2->surfaceType & surfaceType) != 0;
1280     if (!surfaceTypeCompat)
1281     {
1282         return EglBadMatch() << "Surface types are not compatible.";
1283     }
1284 
1285     return NoError();
1286 }
1287 
ValidateCreateImageKHR(const Display * display,gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attributes)1288 Error ValidateCreateImageKHR(const Display *display,
1289                              gl::Context *context,
1290                              EGLenum target,
1291                              EGLClientBuffer buffer,
1292                              const AttributeMap &attributes)
1293 {
1294     ANGLE_TRY(ValidateContext(display, context));
1295 
1296     const DisplayExtensions &displayExtensions = display->getExtensions();
1297 
1298     if (!displayExtensions.imageBase && !displayExtensions.image)
1299     {
1300         // It is out of spec what happens when calling an extension function when the extension is
1301         // not available.
1302         // EGL_BAD_DISPLAY seems like a reasonable error.
1303         return EglBadDisplay() << "EGL_KHR_image not supported.";
1304     }
1305 
1306     // TODO(geofflang): Complete validation from EGL_KHR_image_base:
1307     // If the resource specified by <dpy>, <ctx>, <target>, <buffer> and <attrib_list> is itself an
1308     // EGLImage sibling, the error EGL_BAD_ACCESS is generated.
1309 
1310     for (AttributeMap::const_iterator attributeIter = attributes.begin();
1311          attributeIter != attributes.end(); attributeIter++)
1312     {
1313         EGLAttrib attribute = attributeIter->first;
1314         EGLAttrib value     = attributeIter->second;
1315 
1316         switch (attribute)
1317         {
1318             case EGL_IMAGE_PRESERVED_KHR:
1319                 switch (value)
1320                 {
1321                     case EGL_TRUE:
1322                     case EGL_FALSE:
1323                         break;
1324 
1325                     default:
1326                         return EglBadParameter()
1327                                << "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE.";
1328                 }
1329                 break;
1330 
1331             case EGL_GL_TEXTURE_LEVEL_KHR:
1332                 if (!displayExtensions.glTexture2DImage &&
1333                     !displayExtensions.glTextureCubemapImage && !displayExtensions.glTexture3DImage)
1334                 {
1335                     return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be used "
1336                                                 "without KHR_gl_texture_*_image support.";
1337                 }
1338 
1339                 if (value < 0)
1340                 {
1341                     return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be negative.";
1342                 }
1343                 break;
1344 
1345             case EGL_GL_TEXTURE_ZOFFSET_KHR:
1346                 if (!displayExtensions.glTexture3DImage)
1347                 {
1348                     return EglBadParameter() << "EGL_GL_TEXTURE_ZOFFSET_KHR cannot be used "
1349                                                 "without KHR_gl_texture_3D_image support.";
1350                 }
1351                 break;
1352 
1353             default:
1354                 return EglBadParameter()
1355                        << "invalid attribute: 0x" << std::hex << std::uppercase << attribute;
1356         }
1357     }
1358 
1359     switch (target)
1360     {
1361         case EGL_GL_TEXTURE_2D_KHR:
1362         {
1363             if (!displayExtensions.glTexture2DImage)
1364             {
1365                 return EglBadParameter() << "KHR_gl_texture_2D_image not supported.";
1366             }
1367 
1368             if (buffer == 0)
1369             {
1370                 return EglBadParameter() << "buffer cannot reference a 2D texture with the name 0.";
1371             }
1372 
1373             const gl::Texture *texture =
1374                 context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
1375             if (texture == nullptr || texture->getTarget() != GL_TEXTURE_2D)
1376             {
1377                 return EglBadParameter() << "target is not a 2D texture.";
1378             }
1379 
1380             if (texture->getBoundSurface() != nullptr)
1381             {
1382                 return EglBadAccess() << "texture has a surface bound to it.";
1383             }
1384 
1385             EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
1386             if (texture->getWidth(GL_TEXTURE_2D, static_cast<size_t>(level)) == 0 ||
1387                 texture->getHeight(GL_TEXTURE_2D, static_cast<size_t>(level)) == 0)
1388             {
1389                 return EglBadParameter()
1390                        << "target 2D texture does not have a valid size at specified level.";
1391             }
1392 
1393             ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level));
1394         }
1395         break;
1396 
1397         case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
1398         case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
1399         case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
1400         case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
1401         case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
1402         case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
1403         {
1404             if (!displayExtensions.glTextureCubemapImage)
1405             {
1406                 return EglBadParameter() << "KHR_gl_texture_cubemap_image not supported.";
1407             }
1408 
1409             if (buffer == 0)
1410             {
1411                 return EglBadParameter()
1412                        << "buffer cannot reference a cubemap texture with the name 0.";
1413             }
1414 
1415             const gl::Texture *texture =
1416                 context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
1417             if (texture == nullptr || texture->getTarget() != GL_TEXTURE_CUBE_MAP)
1418             {
1419                 return EglBadParameter() << "target is not a cubemap texture.";
1420             }
1421 
1422             if (texture->getBoundSurface() != nullptr)
1423             {
1424                 return EglBadAccess() << "texture has a surface bound to it.";
1425             }
1426 
1427             EGLAttrib level    = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
1428             GLenum cubeMapFace = egl_gl::EGLCubeMapTargetToGLCubeMapTarget(target);
1429             if (texture->getWidth(cubeMapFace, static_cast<size_t>(level)) == 0 ||
1430                 texture->getHeight(cubeMapFace, static_cast<size_t>(level)) == 0)
1431             {
1432                 return EglBadParameter() << "target cubemap texture does not have a valid "
1433                                             "size at specified level and face.";
1434             }
1435 
1436             ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level));
1437 
1438             if (level == 0 && !texture->isMipmapComplete() &&
1439                 CubeTextureHasUnspecifiedLevel0Face(texture))
1440             {
1441                 return EglBadParameter() << "if level is zero and the texture is incomplete, "
1442                                             "it must have all of its faces specified at level "
1443                                             "zero.";
1444             }
1445         }
1446         break;
1447 
1448         case EGL_GL_TEXTURE_3D_KHR:
1449         {
1450             if (!displayExtensions.glTexture3DImage)
1451             {
1452                 return EglBadParameter() << "KHR_gl_texture_3D_image not supported.";
1453             }
1454 
1455             if (buffer == 0)
1456             {
1457                 return EglBadParameter() << "buffer cannot reference a 3D texture with the name 0.";
1458             }
1459 
1460             const gl::Texture *texture =
1461                 context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
1462             if (texture == nullptr || texture->getTarget() != GL_TEXTURE_3D)
1463             {
1464                 return EglBadParameter() << "target is not a 3D texture.";
1465             }
1466 
1467             if (texture->getBoundSurface() != nullptr)
1468             {
1469                 return EglBadAccess() << "texture has a surface bound to it.";
1470             }
1471 
1472             EGLAttrib level   = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
1473             EGLAttrib zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0);
1474             if (texture->getWidth(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0 ||
1475                 texture->getHeight(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0 ||
1476                 texture->getDepth(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0)
1477             {
1478                 return EglBadParameter()
1479                        << "target 3D texture does not have a valid size at specified level.";
1480             }
1481 
1482             if (static_cast<size_t>(zOffset) >=
1483                 texture->getDepth(GL_TEXTURE_3D, static_cast<size_t>(level)))
1484             {
1485                 return EglBadParameter() << "target 3D texture does not have enough layers "
1486                                             "for the specified Z offset at the specified "
1487                                             "level.";
1488             }
1489 
1490             ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level));
1491         }
1492         break;
1493 
1494         case EGL_GL_RENDERBUFFER_KHR:
1495         {
1496             if (!displayExtensions.glRenderbufferImage)
1497             {
1498                 return EglBadParameter() << "KHR_gl_renderbuffer_image not supported.";
1499             }
1500 
1501             if (attributes.contains(EGL_GL_TEXTURE_LEVEL_KHR))
1502             {
1503                 return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be used in "
1504                                             "conjunction with a renderbuffer target.";
1505             }
1506 
1507             if (buffer == 0)
1508             {
1509                 return EglBadParameter()
1510                        << "buffer cannot reference a renderbuffer with the name 0.";
1511             }
1512 
1513             const gl::Renderbuffer *renderbuffer =
1514                 context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
1515             if (renderbuffer == nullptr)
1516             {
1517                 return EglBadParameter() << "target is not a renderbuffer.";
1518             }
1519 
1520             if (renderbuffer->getSamples() > 0)
1521             {
1522                 return EglBadParameter() << "target renderbuffer cannot be multisampled.";
1523             }
1524         }
1525         break;
1526 
1527         default:
1528             return EglBadParameter()
1529                    << "invalid target: 0x" << std::hex << std::uppercase << target;
1530     }
1531 
1532     return NoError();
1533 }
1534 
ValidateDestroyImageKHR(const Display * display,const Image * image)1535 Error ValidateDestroyImageKHR(const Display *display, const Image *image)
1536 {
1537     ANGLE_TRY(ValidateImage(display, image));
1538 
1539     if (!display->getExtensions().imageBase && !display->getExtensions().image)
1540     {
1541         // It is out of spec what happens when calling an extension function when the extension is
1542         // not available.
1543         // EGL_BAD_DISPLAY seems like a reasonable error.
1544         return EglBadDisplay();
1545     }
1546 
1547     return NoError();
1548 }
1549 
ValidateCreateDeviceANGLE(EGLint device_type,void * native_device,const EGLAttrib * attrib_list)1550 Error ValidateCreateDeviceANGLE(EGLint device_type,
1551                                 void *native_device,
1552                                 const EGLAttrib *attrib_list)
1553 {
1554     const ClientExtensions &clientExtensions = Display::GetClientExtensions();
1555     if (!clientExtensions.deviceCreation)
1556     {
1557         return EglBadAccess() << "Device creation extension not active";
1558     }
1559 
1560     if (attrib_list != nullptr && attrib_list[0] != EGL_NONE)
1561     {
1562         return EglBadAttribute() << "Invalid attrib_list parameter";
1563     }
1564 
1565     switch (device_type)
1566     {
1567         case EGL_D3D11_DEVICE_ANGLE:
1568             if (!clientExtensions.deviceCreationD3D11)
1569             {
1570                 return EglBadAttribute() << "D3D11 device creation extension not active";
1571             }
1572             break;
1573         default:
1574             return EglBadAttribute() << "Invalid device_type parameter";
1575     }
1576 
1577     return NoError();
1578 }
1579 
ValidateReleaseDeviceANGLE(Device * device)1580 Error ValidateReleaseDeviceANGLE(Device *device)
1581 {
1582     const ClientExtensions &clientExtensions = Display::GetClientExtensions();
1583     if (!clientExtensions.deviceCreation)
1584     {
1585         return EglBadAccess() << "Device creation extension not active";
1586     }
1587 
1588     if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device))
1589     {
1590         return EglBadDevice() << "Invalid device parameter";
1591     }
1592 
1593     Display *owningDisplay = device->getOwningDisplay();
1594     if (owningDisplay != nullptr)
1595     {
1596         return EglBadDevice() << "Device must have been created using eglCreateDevice";
1597     }
1598 
1599     return NoError();
1600 }
1601 
ValidateCreateStreamKHR(const Display * display,const AttributeMap & attributes)1602 Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes)
1603 {
1604     ANGLE_TRY(ValidateDisplay(display));
1605 
1606     const DisplayExtensions &displayExtensions = display->getExtensions();
1607     if (!displayExtensions.stream)
1608     {
1609         return EglBadAlloc() << "Stream extension not active";
1610     }
1611 
1612     for (const auto &attributeIter : attributes)
1613     {
1614         EGLAttrib attribute = attributeIter.first;
1615         EGLAttrib value     = attributeIter.second;
1616 
1617         ANGLE_TRY(ValidateStreamAttribute(attribute, value, displayExtensions));
1618     }
1619 
1620     return NoError();
1621 }
1622 
ValidateDestroyStreamKHR(const Display * display,const Stream * stream)1623 Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream)
1624 {
1625     ANGLE_TRY(ValidateStream(display, stream));
1626     return NoError();
1627 }
1628 
ValidateStreamAttribKHR(const Display * display,const Stream * stream,EGLint attribute,EGLint value)1629 Error ValidateStreamAttribKHR(const Display *display,
1630                               const Stream *stream,
1631                               EGLint attribute,
1632                               EGLint value)
1633 {
1634     ANGLE_TRY(ValidateStream(display, stream));
1635 
1636     if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR)
1637     {
1638         return EglBadState() << "Bad stream state";
1639     }
1640 
1641     return ValidateStreamAttribute(attribute, value, display->getExtensions());
1642 }
1643 
ValidateQueryStreamKHR(const Display * display,const Stream * stream,EGLenum attribute,EGLint * value)1644 Error ValidateQueryStreamKHR(const Display *display,
1645                              const Stream *stream,
1646                              EGLenum attribute,
1647                              EGLint *value)
1648 {
1649     ANGLE_TRY(ValidateStream(display, stream));
1650 
1651     switch (attribute)
1652     {
1653         case EGL_STREAM_STATE_KHR:
1654         case EGL_CONSUMER_LATENCY_USEC_KHR:
1655             break;
1656         case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR:
1657             if (!display->getExtensions().streamConsumerGLTexture)
1658             {
1659                 return EglBadAttribute() << "Consumer GLTexture extension not active";
1660             }
1661             break;
1662         default:
1663             return EglBadAttribute() << "Invalid attribute";
1664     }
1665 
1666     return NoError();
1667 }
1668 
ValidateQueryStreamu64KHR(const Display * display,const Stream * stream,EGLenum attribute,EGLuint64KHR * value)1669 Error ValidateQueryStreamu64KHR(const Display *display,
1670                                 const Stream *stream,
1671                                 EGLenum attribute,
1672                                 EGLuint64KHR *value)
1673 {
1674     ANGLE_TRY(ValidateStream(display, stream));
1675 
1676     switch (attribute)
1677     {
1678         case EGL_CONSUMER_FRAME_KHR:
1679         case EGL_PRODUCER_FRAME_KHR:
1680             break;
1681         default:
1682             return EglBadAttribute() << "Invalid attribute";
1683     }
1684 
1685     return NoError();
1686 }
1687 
ValidateStreamConsumerGLTextureExternalKHR(const Display * display,gl::Context * context,const Stream * stream)1688 Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display,
1689                                                  gl::Context *context,
1690                                                  const Stream *stream)
1691 {
1692     ANGLE_TRY(ValidateDisplay(display));
1693     ANGLE_TRY(ValidateContext(display, context));
1694 
1695     const DisplayExtensions &displayExtensions = display->getExtensions();
1696     if (!displayExtensions.streamConsumerGLTexture)
1697     {
1698         return EglBadAccess() << "Stream consumer extension not active";
1699     }
1700 
1701     if (!context->getExtensions().eglStreamConsumerExternal)
1702     {
1703         return EglBadAccess() << "EGL stream consumer external GL extension not enabled";
1704     }
1705 
1706     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
1707     {
1708         return EglBadStream() << "Invalid stream";
1709     }
1710 
1711     if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR)
1712     {
1713         return EglBadState() << "Invalid stream state";
1714     }
1715 
1716     // Lookup the texture and ensure it is correct
1717     gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES);
1718     if (texture == nullptr || texture->getId() == 0)
1719     {
1720         return EglBadAccess() << "No external texture bound";
1721     }
1722 
1723     return NoError();
1724 }
1725 
ValidateStreamConsumerAcquireKHR(const Display * display,gl::Context * context,const Stream * stream)1726 Error ValidateStreamConsumerAcquireKHR(const Display *display,
1727                                        gl::Context *context,
1728                                        const Stream *stream)
1729 {
1730     ANGLE_TRY(ValidateDisplay(display));
1731 
1732     const DisplayExtensions &displayExtensions = display->getExtensions();
1733     if (!displayExtensions.streamConsumerGLTexture)
1734     {
1735         return EglBadAccess() << "Stream consumer extension not active";
1736     }
1737 
1738     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
1739     {
1740         return EglBadStream() << "Invalid stream";
1741     }
1742 
1743     if (!context)
1744     {
1745         return EglBadAccess() << "No GL context current to calling thread.";
1746     }
1747 
1748     ANGLE_TRY(ValidateContext(display, context));
1749 
1750     if (!stream->isConsumerBoundToContext(context))
1751     {
1752         return EglBadAccess() << "Current GL context not associated with stream consumer";
1753     }
1754 
1755     if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB &&
1756         stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV)
1757     {
1758         return EglBadAccess() << "Invalid stream consumer type";
1759     }
1760 
1761     // Note: technically EGL_STREAM_STATE_EMPTY_KHR is a valid state when the timeout is non-zero.
1762     // However, the timeout is effectively ignored since it has no useful functionality with the
1763     // current producers that are implemented, so we don't allow that state
1764     if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
1765         stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
1766     {
1767         return EglBadState() << "Invalid stream state";
1768     }
1769 
1770     return NoError();
1771 }
1772 
ValidateStreamConsumerReleaseKHR(const Display * display,gl::Context * context,const Stream * stream)1773 Error ValidateStreamConsumerReleaseKHR(const Display *display,
1774                                        gl::Context *context,
1775                                        const Stream *stream)
1776 {
1777     ANGLE_TRY(ValidateDisplay(display));
1778 
1779     const DisplayExtensions &displayExtensions = display->getExtensions();
1780     if (!displayExtensions.streamConsumerGLTexture)
1781     {
1782         return EglBadAccess() << "Stream consumer extension not active";
1783     }
1784 
1785     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
1786     {
1787         return EglBadStream() << "Invalid stream";
1788     }
1789 
1790     if (!context)
1791     {
1792         return EglBadAccess() << "No GL context current to calling thread.";
1793     }
1794 
1795     ANGLE_TRY(ValidateContext(display, context));
1796 
1797     if (!stream->isConsumerBoundToContext(context))
1798     {
1799         return EglBadAccess() << "Current GL context not associated with stream consumer";
1800     }
1801 
1802     if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB &&
1803         stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV)
1804     {
1805         return EglBadAccess() << "Invalid stream consumer type";
1806     }
1807 
1808     if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
1809         stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
1810     {
1811         return EglBadState() << "Invalid stream state";
1812     }
1813 
1814     return NoError();
1815 }
1816 
ValidateStreamConsumerGLTextureExternalAttribsNV(const Display * display,gl::Context * context,const Stream * stream,const AttributeMap & attribs)1817 Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display,
1818                                                        gl::Context *context,
1819                                                        const Stream *stream,
1820                                                        const AttributeMap &attribs)
1821 {
1822     ANGLE_TRY(ValidateDisplay(display));
1823 
1824     const DisplayExtensions &displayExtensions = display->getExtensions();
1825     if (!displayExtensions.streamConsumerGLTexture)
1826     {
1827         return EglBadAccess() << "Stream consumer extension not active";
1828     }
1829 
1830     // Although technically not a requirement in spec, the context needs to be checked for support
1831     // for external textures or future logic will cause assertations. This extension is also
1832     // effectively useless without external textures.
1833     if (!context->getExtensions().eglStreamConsumerExternal)
1834     {
1835         return EglBadAccess() << "EGL stream consumer external GL extension not enabled";
1836     }
1837 
1838     if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
1839     {
1840         return EglBadStream() << "Invalid stream";
1841     }
1842 
1843     if (!context)
1844     {
1845         return EglBadAccess() << "No GL context current to calling thread.";
1846     }
1847 
1848     ANGLE_TRY(ValidateContext(display, context));
1849 
1850     if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR)
1851     {
1852         return EglBadState() << "Invalid stream state";
1853     }
1854 
1855     const gl::Caps &glCaps = context->getCaps();
1856 
1857     EGLAttrib colorBufferType = EGL_RGB_BUFFER;
1858     EGLAttrib planeCount      = -1;
1859     EGLAttrib plane[3];
1860     for (int i = 0; i < 3; i++)
1861     {
1862         plane[i] = -1;
1863     }
1864     for (const auto &attributeIter : attribs)
1865     {
1866         EGLAttrib attribute = attributeIter.first;
1867         EGLAttrib value     = attributeIter.second;
1868 
1869         switch (attribute)
1870         {
1871             case EGL_COLOR_BUFFER_TYPE:
1872                 if (value != EGL_RGB_BUFFER && value != EGL_YUV_BUFFER_EXT)
1873                 {
1874                     return EglBadParameter() << "Invalid color buffer type";
1875                 }
1876                 colorBufferType = value;
1877                 break;
1878             case EGL_YUV_NUMBER_OF_PLANES_EXT:
1879                 // planeCount = -1 is a tag for the default plane count so the value must be checked
1880                 // to be positive here to ensure future logic doesn't break on invalid negative
1881                 // inputs
1882                 if (value < 0)
1883                 {
1884                     return EglBadMatch() << "Invalid plane count";
1885                 }
1886                 planeCount = value;
1887                 break;
1888             default:
1889                 if (attribute >= EGL_YUV_PLANE0_TEXTURE_UNIT_NV &&
1890                     attribute <= EGL_YUV_PLANE2_TEXTURE_UNIT_NV)
1891                 {
1892                     if ((value < 0 ||
1893                          value >= static_cast<EGLAttrib>(glCaps.maxCombinedTextureImageUnits)) &&
1894                         value != EGL_NONE)
1895                     {
1896                         return EglBadAccess() << "Invalid texture unit";
1897                     }
1898                     plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value;
1899                 }
1900                 else
1901                 {
1902                     return EglBadAttribute() << "Invalid attribute";
1903                 }
1904         }
1905     }
1906 
1907     if (colorBufferType == EGL_RGB_BUFFER)
1908     {
1909         if (planeCount > 0)
1910         {
1911             return EglBadMatch() << "Plane count must be 0 for RGB buffer";
1912         }
1913         for (int i = 0; i < 3; i++)
1914         {
1915             if (plane[i] != -1)
1916             {
1917                 return EglBadMatch() << "Planes cannot be specified";
1918             }
1919         }
1920 
1921         // Lookup the texture and ensure it is correct
1922         gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES);
1923         if (texture == nullptr || texture->getId() == 0)
1924         {
1925             return EglBadAccess() << "No external texture bound";
1926         }
1927     }
1928     else
1929     {
1930         if (planeCount == -1)
1931         {
1932             planeCount = 2;
1933         }
1934         if (planeCount < 1 || planeCount > 3)
1935         {
1936             return EglBadMatch() << "Invalid YUV plane count";
1937         }
1938         for (EGLAttrib i = planeCount; i < 3; i++)
1939         {
1940             if (plane[i] != -1)
1941             {
1942                 return EglBadMatch() << "Invalid plane specified";
1943             }
1944         }
1945 
1946         // Set to ensure no texture is referenced more than once
1947         std::set<gl::Texture *> textureSet;
1948         for (EGLAttrib i = 0; i < planeCount; i++)
1949         {
1950             if (plane[i] == -1)
1951             {
1952                 return EglBadMatch() << "Not all planes specified";
1953             }
1954             if (plane[i] != EGL_NONE)
1955             {
1956                 gl::Texture *texture = context->getGLState().getSamplerTexture(
1957                     static_cast<unsigned int>(plane[i]), GL_TEXTURE_EXTERNAL_OES);
1958                 if (texture == nullptr || texture->getId() == 0)
1959                 {
1960                     return EglBadAccess()
1961                            << "No external texture bound at one or more specified texture units";
1962                 }
1963                 if (textureSet.find(texture) != textureSet.end())
1964                 {
1965                     return EglBadAccess() << "Multiple planes bound to same texture object";
1966                 }
1967                 textureSet.insert(texture);
1968             }
1969         }
1970     }
1971 
1972     return NoError();
1973 }
1974 
ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display * display,const Stream * stream,const AttributeMap & attribs)1975 Error ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display *display,
1976                                                       const Stream *stream,
1977                                                       const AttributeMap &attribs)
1978 {
1979     ANGLE_TRY(ValidateDisplay(display));
1980 
1981     const DisplayExtensions &displayExtensions = display->getExtensions();
1982     if (!displayExtensions.streamProducerD3DTextureNV12)
1983     {
1984         return EglBadAccess() << "Stream producer extension not active";
1985     }
1986 
1987     ANGLE_TRY(ValidateStream(display, stream));
1988 
1989     if (!attribs.isEmpty())
1990     {
1991         return EglBadAttribute() << "Invalid attribute";
1992     }
1993 
1994     if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR)
1995     {
1996         return EglBadState() << "Stream not in connecting state";
1997     }
1998 
1999     if (stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV ||
2000         stream->getPlaneCount() != 2)
2001     {
2002         return EglBadMatch() << "Incompatible stream consumer type";
2003     }
2004 
2005     return NoError();
2006 }
2007 
ValidateStreamPostD3DTextureNV12ANGLE(const Display * display,const Stream * stream,void * texture,const AttributeMap & attribs)2008 Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display,
2009                                             const Stream *stream,
2010                                             void *texture,
2011                                             const AttributeMap &attribs)
2012 {
2013     ANGLE_TRY(ValidateDisplay(display));
2014 
2015     const DisplayExtensions &displayExtensions = display->getExtensions();
2016     if (!displayExtensions.streamProducerD3DTextureNV12)
2017     {
2018         return EglBadAccess() << "Stream producer extension not active";
2019     }
2020 
2021     ANGLE_TRY(ValidateStream(display, stream));
2022 
2023     for (auto &attributeIter : attribs)
2024     {
2025         EGLAttrib attribute = attributeIter.first;
2026         EGLAttrib value     = attributeIter.second;
2027 
2028         switch (attribute)
2029         {
2030             case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE:
2031                 if (value < 0)
2032                 {
2033                     return EglBadParameter() << "Invalid subresource index";
2034                 }
2035                 break;
2036             default:
2037                 return EglBadAttribute() << "Invalid attribute";
2038         }
2039     }
2040 
2041     if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR &&
2042         stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
2043         stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
2044     {
2045         return EglBadState() << "Stream not fully configured";
2046     }
2047 
2048     if (stream->getProducerType() != Stream::ProducerType::D3D11TextureNV12)
2049     {
2050         return EglBadMatch() << "Incompatible stream producer";
2051     }
2052 
2053     if (texture == nullptr)
2054     {
2055         return EglBadParameter() << "Texture is null";
2056     }
2057 
2058     return stream->validateD3D11NV12Texture(texture);
2059 }
2060 
ValidateGetSyncValuesCHROMIUM(const Display * display,const Surface * surface,const EGLuint64KHR * ust,const EGLuint64KHR * msc,const EGLuint64KHR * sbc)2061 Error ValidateGetSyncValuesCHROMIUM(const Display *display,
2062                                     const Surface *surface,
2063                                     const EGLuint64KHR *ust,
2064                                     const EGLuint64KHR *msc,
2065                                     const EGLuint64KHR *sbc)
2066 {
2067     ANGLE_TRY(ValidateDisplay(display));
2068 
2069     const DisplayExtensions &displayExtensions = display->getExtensions();
2070     if (!displayExtensions.getSyncValues)
2071     {
2072         return EglBadAccess() << "getSyncValues extension not active";
2073     }
2074 
2075     if (display->isDeviceLost())
2076     {
2077         return EglContextLost() << "Context is lost.";
2078     }
2079 
2080     if (surface == EGL_NO_SURFACE)
2081     {
2082         return EglBadSurface() << "getSyncValues surface cannot be EGL_NO_SURFACE";
2083     }
2084 
2085     if (!surface->directComposition())
2086     {
2087         return EglBadSurface() << "getSyncValues surface requires Direct Composition to be enabled";
2088     }
2089 
2090     if (ust == nullptr)
2091     {
2092         return EglBadParameter() << "ust is null";
2093     }
2094 
2095     if (msc == nullptr)
2096     {
2097         return EglBadParameter() << "msc is null";
2098     }
2099 
2100     if (sbc == nullptr)
2101     {
2102         return EglBadParameter() << "sbc is null";
2103     }
2104 
2105     return NoError();
2106 }
2107 
ValidateSwapBuffersWithDamageEXT(const Display * display,const Surface * surface,EGLint * rects,EGLint n_rects)2108 Error ValidateSwapBuffersWithDamageEXT(const Display *display,
2109                                        const Surface *surface,
2110                                        EGLint *rects,
2111                                        EGLint n_rects)
2112 {
2113     Error error = ValidateSurface(display, surface);
2114     if (error.isError())
2115     {
2116         return error;
2117     }
2118 
2119     if (!display->getExtensions().swapBuffersWithDamage)
2120     {
2121         // It is out of spec what happens when calling an extension function when the extension is
2122         // not available. EGL_BAD_DISPLAY seems like a reasonable error.
2123         return EglBadDisplay() << "EGL_EXT_swap_buffers_with_damage is not available.";
2124     }
2125 
2126     if (surface == EGL_NO_SURFACE)
2127     {
2128         return EglBadSurface() << "Swap surface cannot be EGL_NO_SURFACE.";
2129     }
2130 
2131     if (n_rects < 0)
2132     {
2133         return EglBadParameter() << "n_rects cannot be negative.";
2134     }
2135 
2136     if (n_rects > 0 && rects == nullptr)
2137     {
2138         return EglBadParameter() << "n_rects cannot be greater than zero when rects is NULL.";
2139     }
2140 
2141     // TODO(jmadill): Validate Surface is bound to the thread.
2142 
2143     return NoError();
2144 }
2145 
ValidateGetConfigAttrib(const Display * display,const Config * config,EGLint attribute)2146 Error ValidateGetConfigAttrib(const Display *display, const Config *config, EGLint attribute)
2147 {
2148     ANGLE_TRY(ValidateConfig(display, config));
2149     ANGLE_TRY(ValidateConfigAttribute(display, static_cast<EGLAttrib>(attribute)));
2150     return NoError();
2151 }
2152 
ValidateChooseConfig(const Display * display,const AttributeMap & attribs,EGLint configSize,EGLint * numConfig)2153 Error ValidateChooseConfig(const Display *display,
2154                            const AttributeMap &attribs,
2155                            EGLint configSize,
2156                            EGLint *numConfig)
2157 {
2158     ANGLE_TRY(ValidateDisplay(display));
2159     ANGLE_TRY(ValidateConfigAttributes(display, attribs));
2160 
2161     if (numConfig == nullptr)
2162     {
2163         return EglBadParameter() << "num_config cannot be null.";
2164     }
2165 
2166     return NoError();
2167 }
2168 
ValidateGetConfigs(const Display * display,EGLint configSize,EGLint * numConfig)2169 Error ValidateGetConfigs(const Display *display, EGLint configSize, EGLint *numConfig)
2170 {
2171     ANGLE_TRY(ValidateDisplay(display));
2172 
2173     if (numConfig == nullptr)
2174     {
2175         return EglBadParameter() << "num_config cannot be null.";
2176     }
2177 
2178     return NoError();
2179 }
2180 
ValidateGetPlatformDisplay(EGLenum platform,void * native_display,const EGLAttrib * attrib_list)2181 Error ValidateGetPlatformDisplay(EGLenum platform,
2182                                  void *native_display,
2183                                  const EGLAttrib *attrib_list)
2184 {
2185     const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list);
2186     return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap);
2187 }
2188 
ValidateGetPlatformDisplayEXT(EGLenum platform,void * native_display,const EGLint * attrib_list)2189 Error ValidateGetPlatformDisplayEXT(EGLenum platform,
2190                                     void *native_display,
2191                                     const EGLint *attrib_list)
2192 {
2193     const auto &attribMap = AttributeMap::CreateFromIntArray(attrib_list);
2194     return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap);
2195 }
2196 
ValidateProgramCacheGetAttribANGLE(const Display * display,EGLenum attrib)2197 Error ValidateProgramCacheGetAttribANGLE(const Display *display, EGLenum attrib)
2198 {
2199     ANGLE_TRY(ValidateDisplay(display));
2200 
2201     if (!display->getExtensions().programCacheControl)
2202     {
2203         return EglBadAccess() << "Extension not supported";
2204     }
2205 
2206     switch (attrib)
2207     {
2208         case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
2209         case EGL_PROGRAM_CACHE_SIZE_ANGLE:
2210             break;
2211 
2212         default:
2213             return EglBadParameter() << "Invalid program cache attribute.";
2214     }
2215 
2216     return NoError();
2217 }
2218 
ValidateProgramCacheQueryANGLE(const Display * display,EGLint index,void * key,EGLint * keysize,void * binary,EGLint * binarysize)2219 Error ValidateProgramCacheQueryANGLE(const Display *display,
2220                                      EGLint index,
2221                                      void *key,
2222                                      EGLint *keysize,
2223                                      void *binary,
2224                                      EGLint *binarysize)
2225 {
2226     ANGLE_TRY(ValidateDisplay(display));
2227 
2228     if (!display->getExtensions().programCacheControl)
2229     {
2230         return EglBadAccess() << "Extension not supported";
2231     }
2232 
2233     if (index < 0 || index >= display->programCacheGetAttrib(EGL_PROGRAM_CACHE_SIZE_ANGLE))
2234     {
2235         return EglBadParameter() << "Program index out of range.";
2236     }
2237 
2238     if (keysize == nullptr || binarysize == nullptr)
2239     {
2240         return EglBadParameter() << "keysize and binarysize must always be valid pointers.";
2241     }
2242 
2243     if (binary && *keysize != static_cast<EGLint>(gl::kProgramHashLength))
2244     {
2245         return EglBadParameter() << "Invalid program key size.";
2246     }
2247 
2248     if ((key == nullptr) != (binary == nullptr))
2249     {
2250         return EglBadParameter() << "key and binary must both be null or both non-null.";
2251     }
2252 
2253     return NoError();
2254 }
2255 
ValidateProgramCachePopulateANGLE(const Display * display,const void * key,EGLint keysize,const void * binary,EGLint binarysize)2256 Error ValidateProgramCachePopulateANGLE(const Display *display,
2257                                         const void *key,
2258                                         EGLint keysize,
2259                                         const void *binary,
2260                                         EGLint binarysize)
2261 {
2262     ANGLE_TRY(ValidateDisplay(display));
2263 
2264     if (!display->getExtensions().programCacheControl)
2265     {
2266         return EglBadAccess() << "Extension not supported";
2267     }
2268 
2269     if (keysize != static_cast<EGLint>(gl::kProgramHashLength))
2270     {
2271         return EglBadParameter() << "Invalid program key size.";
2272     }
2273 
2274     if (key == nullptr || binary == nullptr)
2275     {
2276         return EglBadParameter() << "null pointer in arguments.";
2277     }
2278 
2279     // Upper bound for binarysize is arbitrary.
2280     if (binarysize <= 0 || binarysize > egl::kProgramCacheSizeAbsoluteMax)
2281     {
2282         return EglBadParameter() << "binarysize out of valid range.";
2283     }
2284 
2285     return NoError();
2286 }
2287 
ValidateProgramCacheResizeANGLE(const Display * display,EGLint limit,EGLenum mode)2288 Error ValidateProgramCacheResizeANGLE(const Display *display, EGLint limit, EGLenum mode)
2289 {
2290     ANGLE_TRY(ValidateDisplay(display));
2291 
2292     if (!display->getExtensions().programCacheControl)
2293     {
2294         return EglBadAccess() << "Extension not supported";
2295     }
2296 
2297     if (limit < 0)
2298     {
2299         return EglBadParameter() << "limit must be non-negative.";
2300     }
2301 
2302     switch (mode)
2303     {
2304         case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
2305         case EGL_PROGRAM_CACHE_TRIM_ANGLE:
2306             break;
2307 
2308         default:
2309             return EglBadParameter() << "Invalid cache resize mode.";
2310     }
2311 
2312     return NoError();
2313 }
2314 
ValidateSurfaceAttrib(const Display * display,const Surface * surface,EGLint attribute,EGLint value)2315 Error ValidateSurfaceAttrib(const Display *display,
2316                             const Surface *surface,
2317                             EGLint attribute,
2318                             EGLint value)
2319 {
2320     ANGLE_TRY(ValidateDisplay(display));
2321     ANGLE_TRY(ValidateSurface(display, surface));
2322 
2323     if (surface == EGL_NO_SURFACE)
2324     {
2325         return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE.";
2326     }
2327 
2328     switch (attribute)
2329     {
2330         case EGL_MIPMAP_LEVEL:
2331             break;
2332 
2333         case EGL_MULTISAMPLE_RESOLVE:
2334             switch (value)
2335             {
2336                 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
2337                     break;
2338 
2339                 case EGL_MULTISAMPLE_RESOLVE_BOX:
2340                     if ((surface->getConfig()->surfaceType & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) == 0)
2341                     {
2342                         return EglBadMatch()
2343                                << "Surface does not support EGL_MULTISAMPLE_RESOLVE_BOX.";
2344                     }
2345                     break;
2346 
2347                 default:
2348                     return EglBadAttribute() << "Invalid multisample resolve type.";
2349             }
2350 
2351         case EGL_SWAP_BEHAVIOR:
2352             switch (value)
2353             {
2354                 case EGL_BUFFER_PRESERVED:
2355                     if ((surface->getConfig()->surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == 0)
2356                     {
2357                         return EglBadMatch()
2358                                << "Surface does not support EGL_SWAP_BEHAVIOR_PRESERVED.";
2359                     }
2360                     break;
2361 
2362                 case EGL_BUFFER_DESTROYED:
2363                     break;
2364 
2365                 default:
2366                     return EglBadAttribute() << "Invalid swap behaviour.";
2367             }
2368 
2369         default:
2370             return EglBadAttribute() << "Invalid surface attribute.";
2371     }
2372 
2373     return NoError();
2374 }
2375 
ValidateQuerySurface(const Display * display,const Surface * surface,EGLint attribute,EGLint * value)2376 Error ValidateQuerySurface(const Display *display,
2377                            const Surface *surface,
2378                            EGLint attribute,
2379                            EGLint *value)
2380 {
2381     ANGLE_TRY(ValidateDisplay(display));
2382     ANGLE_TRY(ValidateSurface(display, surface));
2383 
2384     if (surface == EGL_NO_SURFACE)
2385     {
2386         return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE.";
2387     }
2388 
2389     switch (attribute)
2390     {
2391         case EGL_GL_COLORSPACE:
2392         case EGL_VG_ALPHA_FORMAT:
2393         case EGL_VG_COLORSPACE:
2394         case EGL_CONFIG_ID:
2395         case EGL_HEIGHT:
2396         case EGL_HORIZONTAL_RESOLUTION:
2397         case EGL_LARGEST_PBUFFER:
2398         case EGL_MIPMAP_TEXTURE:
2399         case EGL_MIPMAP_LEVEL:
2400         case EGL_MULTISAMPLE_RESOLVE:
2401         case EGL_PIXEL_ASPECT_RATIO:
2402         case EGL_RENDER_BUFFER:
2403         case EGL_SWAP_BEHAVIOR:
2404         case EGL_TEXTURE_FORMAT:
2405         case EGL_TEXTURE_TARGET:
2406         case EGL_VERTICAL_RESOLUTION:
2407         case EGL_WIDTH:
2408             break;
2409 
2410         case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
2411             if (!display->getExtensions().postSubBuffer)
2412             {
2413                 return EglBadAttribute() << "EGL_POST_SUB_BUFFER_SUPPORTED_NV cannot be used "
2414                                             "without EGL_ANGLE_surface_orientation support.";
2415             }
2416             break;
2417 
2418         case EGL_FIXED_SIZE_ANGLE:
2419             if (!display->getExtensions().windowFixedSize)
2420             {
2421                 return EglBadAttribute() << "EGL_FIXED_SIZE_ANGLE cannot be used without "
2422                                             "EGL_ANGLE_window_fixed_size support.";
2423             }
2424             break;
2425 
2426         case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
2427             if (!display->getExtensions().flexibleSurfaceCompatibility)
2428             {
2429                 return EglBadAttribute()
2430                        << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be "
2431                           "used without EGL_ANGLE_flexible_surface_compatibility support.";
2432             }
2433             break;
2434 
2435         case EGL_SURFACE_ORIENTATION_ANGLE:
2436             if (!display->getExtensions().surfaceOrientation)
2437             {
2438                 return EglBadAttribute() << "EGL_SURFACE_ORIENTATION_ANGLE cannot be "
2439                                             "queried without "
2440                                             "EGL_ANGLE_surface_orientation support.";
2441             }
2442             break;
2443 
2444         case EGL_DIRECT_COMPOSITION_ANGLE:
2445             if (!display->getExtensions().directComposition)
2446             {
2447                 return EglBadAttribute() << "EGL_DIRECT_COMPOSITION_ANGLE cannot be "
2448                                             "used without "
2449                                             "EGL_ANGLE_direct_composition support.";
2450             }
2451             break;
2452 
2453         case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
2454             if (!display->getExtensions().robustResourceInitialization)
2455             {
2456                 return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be "
2457                                             "used without EGL_ANGLE_robust_resource_initialization "
2458                                             "support.";
2459             }
2460             break;
2461 
2462         default:
2463             return EglBadAttribute() << "Invalid surface attribute.";
2464     }
2465 
2466     return NoError();
2467 }
2468 
ValidateQueryContext(const Display * display,const gl::Context * context,EGLint attribute,EGLint * value)2469 Error ValidateQueryContext(const Display *display,
2470                            const gl::Context *context,
2471                            EGLint attribute,
2472                            EGLint *value)
2473 {
2474     ANGLE_TRY(ValidateDisplay(display));
2475     ANGLE_TRY(ValidateContext(display, context));
2476 
2477     switch (attribute)
2478     {
2479         case EGL_CONFIG_ID:
2480         case EGL_CONTEXT_CLIENT_TYPE:
2481         case EGL_CONTEXT_CLIENT_VERSION:
2482         case EGL_RENDER_BUFFER:
2483             break;
2484 
2485         case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
2486             if (!display->getExtensions().robustResourceInitialization)
2487             {
2488                 return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be "
2489                                             "used without EGL_ANGLE_robust_resource_initialization "
2490                                             "support.";
2491             }
2492             break;
2493 
2494         default:
2495             return EglBadAttribute() << "Invalid context attribute.";
2496     }
2497 
2498     return NoError();
2499 }
2500 
2501 }  // namespace egl
2502