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