1//
2// Copyright 2016 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationEGL.cpp: Validation functions for generic EGL entry point parameters
8
9#include "libANGLE/validationEGL_autogen.h"
10
11#include "common/utilities.h"
12#include "libANGLE/Config.h"
13#include "libANGLE/Context.h"
14#include "libANGLE/Device.h"
15#include "libANGLE/Display.h"
16#include "libANGLE/EGLSync.h"
17#include "libANGLE/Image.h"
18#include "libANGLE/Stream.h"
19#include "libANGLE/Surface.h"
20#include "libANGLE/Texture.h"
21#include "libANGLE/Thread.h"
22#include "libANGLE/formatutils.h"
23#include "libANGLE/renderer/DisplayImpl.h"
24
25#include <EGL/eglext.h>
26
27namespace egl
28{
29namespace
30{
31size_t GetMaximumMipLevel(const gl::Context *context, gl::TextureType type)
32{
33 const gl::Caps &caps = context->getCaps();
34
35 int maxDimension = 0;
36 switch (type)
37 {
38 case gl::TextureType::_2D:
39 case gl::TextureType::_2DArray:
40 case gl::TextureType::_2DMultisample:
41 maxDimension = caps.max2DTextureSize;
42 break;
43 case gl::TextureType::Rectangle:
44 maxDimension = caps.maxRectangleTextureSize;
45 break;
46 case gl::TextureType::CubeMap:
47 maxDimension = caps.maxCubeMapTextureSize;
48 break;
49 case gl::TextureType::_3D:
50 maxDimension = caps.max3DTextureSize;
51 break;
52
53 default:
54 UNREACHABLE();
55 }
56
57 return gl::log2(x: maxDimension);
58}
59
60bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::Texture *texture)
61{
62 size_t maxMip = GetMaximumMipLevel(context, type: texture->getType());
63 for (size_t level = 1; level < maxMip; level++)
64 {
65 if (texture->getType() == gl::TextureType::CubeMap)
66 {
67 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
68 {
69 if (texture->getFormat(target: face, level).valid())
70 {
71 return true;
72 }
73 }
74 }
75 else
76 {
77 if (texture->getFormat(target: gl::NonCubeTextureTypeToTarget(type: texture->getType()), level)
78 .valid())
79 {
80 return true;
81 }
82 }
83 }
84
85 return false;
86}
87
88bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture)
89{
90 ASSERT(texture->getType() == gl::TextureType::CubeMap);
91 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
92 {
93 if (!texture->getFormat(target: face, level: 0).valid())
94 {
95 return true;
96 }
97 }
98
99 return false;
100}
101
102bool ValidateStreamAttribute(const ValidationContext *val,
103 const EGLAttrib attribute,
104 const EGLAttrib value,
105 const DisplayExtensions &extensions)
106{
107 switch (attribute)
108 {
109 case EGL_STREAM_STATE_KHR:
110 case EGL_PRODUCER_FRAME_KHR:
111 case EGL_CONSUMER_FRAME_KHR:
112 val->setError(EGL_BAD_ACCESS, message: "Attempt to initialize readonly parameter");
113 return false;
114 case EGL_CONSUMER_LATENCY_USEC_KHR:
115 // Technically not in spec but a latency < 0 makes no sense so we check it
116 if (value < 0)
117 {
118 val->setError(EGL_BAD_PARAMETER, message: "Latency must be positive");
119 return false;
120 }
121 break;
122 case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR:
123 if (!extensions.streamConsumerGLTexture)
124 {
125 val->setError(EGL_BAD_ATTRIBUTE, message: "Consumer GL extension not enabled");
126 return false;
127 }
128 // Again not in spec but it should be positive anyways
129 if (value < 0)
130 {
131 val->setError(EGL_BAD_PARAMETER, message: "Timeout must be positive");
132 return false;
133 }
134 break;
135 default:
136 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid stream attribute");
137 return false;
138 }
139 return true;
140}
141
142bool ValidateCreateImageMipLevelCommon(const ValidationContext *val,
143 const gl::Context *context,
144 const gl::Texture *texture,
145 EGLAttrib level)
146{
147 // Note that the spec EGL_create_image spec does not explicitly specify an error
148 // when the level is outside the base/max level range, but it does mention that the
149 // level "must be a part of the complete texture object <buffer>". It can be argued
150 // that out-of-range levels are not a part of the complete texture.
151 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
152 if (level > 0 &&
153 (!texture->isMipmapComplete() || static_cast<GLuint>(level) < effectiveBaseLevel ||
154 static_cast<GLuint>(level) > texture->getTextureState().getMipmapMaxLevel()))
155 {
156 val->setError(EGL_BAD_PARAMETER, message: "texture must be complete if level is non-zero.");
157 return false;
158 }
159
160 if (level == 0 && !texture->isMipmapComplete() &&
161 TextureHasNonZeroMipLevelsSpecified(context, texture))
162 {
163 val->setError(EGL_BAD_PARAMETER,
164 message: "if level is zero and the texture is incomplete, it must "
165 "have no mip levels specified except zero.");
166 return false;
167 }
168
169 return true;
170}
171
172bool ValidateConfigAttribute(const ValidationContext *val,
173 const Display *display,
174 EGLAttrib attribute)
175{
176 switch (attribute)
177 {
178 case EGL_BUFFER_SIZE:
179 case EGL_ALPHA_SIZE:
180 case EGL_BLUE_SIZE:
181 case EGL_GREEN_SIZE:
182 case EGL_RED_SIZE:
183 case EGL_DEPTH_SIZE:
184 case EGL_STENCIL_SIZE:
185 case EGL_CONFIG_CAVEAT:
186 case EGL_CONFIG_ID:
187 case EGL_LEVEL:
188 case EGL_NATIVE_RENDERABLE:
189 case EGL_NATIVE_VISUAL_ID:
190 case EGL_NATIVE_VISUAL_TYPE:
191 case EGL_SAMPLES:
192 case EGL_SAMPLE_BUFFERS:
193 case EGL_SURFACE_TYPE:
194 case EGL_TRANSPARENT_TYPE:
195 case EGL_TRANSPARENT_BLUE_VALUE:
196 case EGL_TRANSPARENT_GREEN_VALUE:
197 case EGL_TRANSPARENT_RED_VALUE:
198 case EGL_BIND_TO_TEXTURE_RGB:
199 case EGL_BIND_TO_TEXTURE_RGBA:
200 case EGL_MIN_SWAP_INTERVAL:
201 case EGL_MAX_SWAP_INTERVAL:
202 case EGL_LUMINANCE_SIZE:
203 case EGL_ALPHA_MASK_SIZE:
204 case EGL_COLOR_BUFFER_TYPE:
205 case EGL_RENDERABLE_TYPE:
206 case EGL_MATCH_NATIVE_PIXMAP:
207 case EGL_CONFORMANT:
208 case EGL_MAX_PBUFFER_WIDTH:
209 case EGL_MAX_PBUFFER_HEIGHT:
210 case EGL_MAX_PBUFFER_PIXELS:
211 break;
212
213 case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
214 if (!display->getExtensions().surfaceOrientation)
215 {
216 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_ANGLE_surface_orientation is not enabled.");
217 return false;
218 }
219 break;
220
221 case EGL_COLOR_COMPONENT_TYPE_EXT:
222 if (!display->getExtensions().pixelFormatFloat)
223 {
224 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_EXT_pixel_format_float is not enabled.");
225 return false;
226 }
227 break;
228
229 case EGL_RECORDABLE_ANDROID:
230 if (!display->getExtensions().recordable)
231 {
232 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_ANDROID_recordable is not enabled.");
233 return false;
234 }
235 break;
236
237 case EGL_FRAMEBUFFER_TARGET_ANDROID:
238 if (!display->getExtensions().framebufferTargetANDROID)
239 {
240 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_ANDROID_framebuffer_target is not enabled.");
241 return false;
242 }
243 break;
244
245 case EGL_BIND_TO_TEXTURE_TARGET_ANGLE:
246 if (!display->getExtensions().iosurfaceClientBuffer)
247 {
248 val->setError(EGL_BAD_ATTRIBUTE,
249 message: "EGL_ANGLE_iosurface_client_buffer is not enabled.");
250 return false;
251 }
252 break;
253
254 case EGL_Y_INVERTED_NOK:
255 if (!display->getExtensions().textureFromPixmapNOK)
256 {
257 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_NOK_texture_from_pixmap is not enabled.");
258 return false;
259 }
260 break;
261
262 case EGL_MATCH_FORMAT_KHR:
263 if (!display->getExtensions().lockSurface3KHR)
264 {
265 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_KHR_lock_surface3 is not enabled.");
266 return false;
267 }
268 break;
269
270 default:
271 val->setError(EGL_BAD_ATTRIBUTE, message: "Unknown attribute: 0x%04" PRIxPTR "X", attribute);
272 return false;
273 }
274
275 return true;
276}
277
278bool ValidateConfigAttributeValue(const ValidationContext *val,
279 const Display *display,
280 EGLAttrib attribute,
281 EGLAttrib value)
282{
283 switch (attribute)
284 {
285
286 case EGL_BIND_TO_TEXTURE_RGB:
287 case EGL_BIND_TO_TEXTURE_RGBA:
288 switch (value)
289 {
290 case EGL_DONT_CARE:
291 case EGL_TRUE:
292 case EGL_FALSE:
293 break;
294 default:
295 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_bind_to_texture invalid attribute: 0x%X",
296 static_cast<uint32_t>(value));
297 return false;
298 }
299 break;
300
301 case EGL_COLOR_BUFFER_TYPE:
302 switch (value)
303 {
304 case EGL_RGB_BUFFER:
305 case EGL_LUMINANCE_BUFFER:
306 // EGL_DONT_CARE doesn't match the spec, but does match dEQP usage
307 case EGL_DONT_CARE:
308 break;
309 default:
310 val->setError(EGL_BAD_ATTRIBUTE,
311 message: "EGL_color_buffer_type invalid attribute: 0x%X",
312 static_cast<uint32_t>(value));
313 return false;
314 }
315 break;
316
317 case EGL_NATIVE_RENDERABLE:
318 switch (value)
319 {
320 case EGL_DONT_CARE:
321 case EGL_TRUE:
322 case EGL_FALSE:
323 break;
324 default:
325 val->setError(EGL_BAD_ATTRIBUTE,
326 message: "EGL_native_renderable invalid attribute: 0x%X",
327 static_cast<uint32_t>(value));
328 return false;
329 }
330 break;
331
332 case EGL_TRANSPARENT_TYPE:
333 switch (value)
334 {
335 case EGL_NONE:
336 case EGL_TRANSPARENT_RGB:
337 // EGL_DONT_CARE doesn't match the spec, but does match dEQP usage
338 case EGL_DONT_CARE:
339 break;
340 default:
341 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_transparent_type invalid attribute: 0x%X",
342 static_cast<uint32_t>(value));
343 return false;
344 }
345 break;
346
347 case EGL_RECORDABLE_ANDROID:
348 switch (value)
349 {
350 case EGL_TRUE:
351 case EGL_FALSE:
352 case EGL_DONT_CARE:
353 break;
354 default:
355 val->setError(EGL_BAD_ATTRIBUTE,
356 message: "EGL_RECORDABLE_ANDROID invalid attribute: 0x%X",
357 static_cast<uint32_t>(value));
358 return false;
359 }
360 break;
361
362 case EGL_COLOR_COMPONENT_TYPE_EXT:
363 switch (value)
364 {
365 case EGL_COLOR_COMPONENT_TYPE_FIXED_EXT:
366 case EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT:
367 case EGL_DONT_CARE:
368 break;
369 default:
370 val->setError(EGL_BAD_ATTRIBUTE,
371 message: "EGL_COLOR_COMPONENT_TYPE_EXT invalid attribute: 0x%X",
372 static_cast<uint32_t>(value));
373 return false;
374 }
375 break;
376
377 case EGL_MATCH_FORMAT_KHR:
378 switch (value)
379 {
380 case EGL_FORMAT_RGB_565_KHR:
381 case EGL_FORMAT_RGBA_8888_KHR:
382 case EGL_FORMAT_RGB_565_EXACT_KHR:
383 case EGL_FORMAT_RGBA_8888_EXACT_KHR:
384 break;
385 default:
386 val->setError(EGL_BAD_ATTRIBUTE,
387 message: "EGL_KHR_lock_surface3 invalid attribute: 0x%X",
388 static_cast<uint32_t>(value));
389 return false;
390 }
391 break;
392
393 default:
394 break;
395 }
396
397 return true;
398}
399
400bool ValidateConfigAttributes(const ValidationContext *val,
401 const Display *display,
402 const AttributeMap &attributes)
403{
404 ANGLE_VALIDATION_TRY(attributes.validate(val, display, ValidateConfigAttribute));
405
406 for (const auto &attrib : attributes)
407 {
408 EGLAttrib pname = attrib.first;
409 EGLAttrib value = attrib.second;
410 ANGLE_VALIDATION_TRY(ValidateConfigAttributeValue(val, display, pname, value));
411 }
412
413 return true;
414}
415
416bool ValidateColorspaceAttribute(const ValidationContext *val,
417 const DisplayExtensions &displayExtensions,
418 EGLAttrib colorSpace)
419{
420 switch (colorSpace)
421 {
422 case EGL_GL_COLORSPACE_SRGB:
423 break;
424 case EGL_GL_COLORSPACE_LINEAR:
425 break;
426 case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
427 if (!displayExtensions.glColorspaceDisplayP3Linear &&
428 !displayExtensions.eglColorspaceAttributePassthroughANGLE)
429 {
430 val->setError(EGL_BAD_ATTRIBUTE,
431 message: "EXT_gl_colorspace_display_p3_linear is not available.");
432 return false;
433 }
434 break;
435 case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
436 if (!displayExtensions.glColorspaceDisplayP3 &&
437 !displayExtensions.eglColorspaceAttributePassthroughANGLE)
438 {
439 val->setError(EGL_BAD_ATTRIBUTE, message: "EXT_gl_colorspace_display_p3 is not available.");
440 return false;
441 }
442 break;
443 case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
444 if (!displayExtensions.glColorspaceDisplayP3Passthrough &&
445 !displayExtensions.eglColorspaceAttributePassthroughANGLE)
446 {
447 val->setError(EGL_BAD_ATTRIBUTE,
448 message: "EGL_EXT_gl_colorspace_display_p3_passthrough is not available.");
449 return false;
450 }
451 break;
452 case EGL_GL_COLORSPACE_SCRGB_EXT:
453 if (!displayExtensions.glColorspaceScrgb &&
454 !displayExtensions.eglColorspaceAttributePassthroughANGLE)
455 {
456 val->setError(EGL_BAD_ATTRIBUTE, message: "EXT_gl_colorspace_scrgb is not available.");
457 return false;
458 }
459 break;
460 case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
461 if (!displayExtensions.glColorspaceScrgbLinear &&
462 !displayExtensions.eglColorspaceAttributePassthroughANGLE)
463 {
464 val->setError(EGL_BAD_ATTRIBUTE,
465 message: "EXT_gl_colorspace_scrgb_linear is not available.");
466 return false;
467 }
468 break;
469 default:
470 val->setError(EGL_BAD_ATTRIBUTE);
471 return false;
472 }
473 return true;
474}
475bool ValidatePlatformType(const ValidationContext *val,
476 const ClientExtensions &clientExtensions,
477 EGLAttrib platformType)
478{
479 switch (platformType)
480 {
481 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
482 break;
483
484 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
485 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
486 if (!clientExtensions.platformANGLED3D)
487 {
488 val->setError(EGL_BAD_ATTRIBUTE, message: "Direct3D platform is unsupported.");
489 return false;
490 }
491 break;
492
493 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
494 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
495 if (!clientExtensions.platformANGLEOpenGL)
496 {
497 val->setError(EGL_BAD_ATTRIBUTE, message: "OpenGL platform is unsupported.");
498 return false;
499 }
500 break;
501
502 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
503 if (!clientExtensions.platformANGLENULL)
504 {
505 val->setError(EGL_BAD_ATTRIBUTE,
506 message: "Display type EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE "
507 "requires EGL_ANGLE_platform_angle_null.");
508 return false;
509 }
510 break;
511
512 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
513 if (!clientExtensions.platformANGLEVulkan)
514 {
515 val->setError(EGL_BAD_ATTRIBUTE, message: "Vulkan platform is unsupported.");
516 return false;
517 }
518 break;
519
520 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
521 if (!clientExtensions.platformANGLEMetal)
522 {
523 val->setError(EGL_BAD_ATTRIBUTE, message: "Metal platform is unsupported.");
524 return false;
525 }
526 break;
527
528 default:
529 val->setError(EGL_BAD_ATTRIBUTE, message: "Unknown platform type.");
530 return false;
531 }
532
533 return true;
534}
535
536bool ValidateGetPlatformDisplayCommon(const ValidationContext *val,
537 EGLenum platform,
538 const void *native_display,
539 const AttributeMap &attribMap)
540{
541 const ClientExtensions &clientExtensions = Display::GetClientExtensions();
542
543 switch (platform)
544 {
545 case EGL_PLATFORM_ANGLE_ANGLE:
546 if (!clientExtensions.platformANGLE)
547 {
548 val->setError(EGL_BAD_PARAMETER, message: "Platform ANGLE extension is not active");
549 return false;
550 }
551 break;
552 case EGL_PLATFORM_DEVICE_EXT:
553 if (!clientExtensions.platformDevice)
554 {
555 val->setError(EGL_BAD_PARAMETER, message: "Platform Device extension is not active");
556 return false;
557 }
558 break;
559 case EGL_PLATFORM_GBM_KHR:
560 if (!clientExtensions.platformGbmKHR)
561 {
562 val->setError(EGL_BAD_PARAMETER, message: "Platform GBM extension is not active");
563 return false;
564 }
565 break;
566 case EGL_PLATFORM_WAYLAND_EXT:
567 if (!clientExtensions.platformWaylandEXT)
568 {
569 val->setError(EGL_BAD_PARAMETER, message: "Platform Wayland extension is not active");
570 return false;
571 }
572 break;
573 default:
574 val->setError(EGL_BAD_CONFIG, message: "Bad platform type.");
575 return false;
576 }
577
578 attribMap.initializeWithoutValidation();
579
580 if (platform != EGL_PLATFORM_DEVICE_EXT)
581 {
582 EGLAttrib platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
583 bool enableAutoTrimSpecified = false;
584 bool enableD3D11on12 = false;
585 bool presentPathSpecified = false;
586 bool luidSpecified = false;
587 bool deviceIdSpecified = false;
588
589 Optional<EGLAttrib> majorVersion;
590 Optional<EGLAttrib> minorVersion;
591 Optional<EGLAttrib> deviceType;
592 Optional<EGLAttrib> eglHandle;
593
594 for (const auto &curAttrib : attribMap)
595 {
596 const EGLAttrib value = curAttrib.second;
597
598 switch (curAttrib.first)
599 {
600 case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
601 {
602 ANGLE_VALIDATION_TRY(ValidatePlatformType(val, clientExtensions, value));
603 platformType = value;
604 break;
605 }
606
607 case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
608 if (value != EGL_DONT_CARE)
609 {
610 majorVersion = value;
611 }
612 break;
613
614 case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
615 if (value != EGL_DONT_CARE)
616 {
617 minorVersion = value;
618 }
619 break;
620
621 case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
622 switch (value)
623 {
624 case EGL_TRUE:
625 case EGL_FALSE:
626 break;
627 default:
628 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid automatic trim attribute");
629 return false;
630 }
631 enableAutoTrimSpecified = true;
632 break;
633
634 case EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE:
635 if (!clientExtensions.platformANGLED3D ||
636 !clientExtensions.platformANGLED3D11ON12)
637 {
638 val->setError(EGL_BAD_ATTRIBUTE,
639 message: "EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE extension not active.");
640 return false;
641 }
642
643 switch (value)
644 {
645 case EGL_TRUE:
646 case EGL_FALSE:
647 break;
648 default:
649 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid D3D11on12 attribute");
650 return false;
651 }
652 enableD3D11on12 = true;
653 break;
654
655 case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE:
656 if (!clientExtensions.experimentalPresentPath)
657 {
658 val->setError(EGL_BAD_ATTRIBUTE,
659 message: "EGL_ANGLE_experimental_present_path extension not active");
660 return false;
661 }
662
663 switch (value)
664 {
665 case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE:
666 case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE:
667 break;
668 default:
669 val->setError(EGL_BAD_ATTRIBUTE,
670 message: "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE");
671 return false;
672 }
673 presentPathSpecified = true;
674 break;
675
676 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
677 switch (value)
678 {
679 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
680 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
681 break;
682
683 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE:
684 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE:
685 if (!clientExtensions.platformANGLED3D)
686 {
687 val->setError(EGL_BAD_ATTRIBUTE,
688 message: "EGL_ANGLE_platform_angle_d3d is not supported");
689 return false;
690 }
691 break;
692
693 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE:
694 if (!clientExtensions.platformANGLEDeviceTypeEGLANGLE)
695 {
696 val->setError(EGL_BAD_ATTRIBUTE,
697 message: "EGL_ANGLE_platform_angle_device_type_"
698 "egl_angle is not supported");
699 return false;
700 }
701 break;
702
703 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE:
704 if (!clientExtensions.platformANGLEDeviceTypeSwiftShader)
705 {
706 val->setError(EGL_BAD_ATTRIBUTE,
707 message: "EGL_ANGLE_platform_angle_device_type_"
708 "swiftshader is not supported");
709 return false;
710 }
711 break;
712
713 default:
714 val->setError(EGL_BAD_ATTRIBUTE,
715 message: "Invalid value for "
716 "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE "
717 "attrib");
718 return false;
719 }
720 deviceType = value;
721 break;
722
723 case EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE:
724 if (!clientExtensions.platformANGLE)
725 {
726 val->setError(EGL_BAD_ATTRIBUTE,
727 message: "EGL_ANGLE_platform_angle extension not active");
728 return false;
729 }
730 if (value != EGL_TRUE && value != EGL_FALSE && value != EGL_DONT_CARE)
731 {
732 val->setError(EGL_BAD_ATTRIBUTE,
733 message: "EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE "
734 "must be EGL_TRUE, EGL_FALSE, or "
735 "EGL_DONT_CARE.");
736 return false;
737 }
738 break;
739
740 case EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE:
741 if (value != EGL_DONT_CARE)
742 {
743 eglHandle = value;
744 }
745 break;
746
747 case EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE:
748 case EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE:
749 luidSpecified = true;
750 break;
751 case EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE:
752 // The property does not have an effect if it's not active, so do not check
753 // for non-support.
754 switch (value)
755 {
756 case EGL_FALSE:
757 case EGL_TRUE:
758 break;
759 default:
760 val->setError(EGL_BAD_ATTRIBUTE,
761 message: "Invalid value for "
762 "EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_"
763 "EAGL_ANGLE attrib");
764 return false;
765 }
766 break;
767 case EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE:
768 // The property does not have an effect if it's not active, so do not check
769 // for non-support.
770 switch (value)
771 {
772 case EGL_FALSE:
773 case EGL_TRUE:
774 break;
775 default:
776 val->setError(EGL_BAD_ATTRIBUTE,
777 message: "Invalid value for "
778 "EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_"
779 "CGL_ANGLE attrib");
780 return false;
781 }
782 break;
783 case EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE:
784 case EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE:
785 case EGL_PLATFORM_ANGLE_DISPLAY_KEY_ANGLE:
786 if (!clientExtensions.platformANGLEDeviceId)
787 {
788 val->setError(EGL_BAD_ATTRIBUTE,
789 message: "EGL_ANGLE_platform_angle_device_id is not supported");
790 return false;
791 }
792 deviceIdSpecified = true;
793 break;
794 default:
795 break;
796 }
797 }
798
799 if (!majorVersion.valid() && minorVersion.valid())
800 {
801 val->setError(EGL_BAD_ATTRIBUTE,
802 message: "Must specify major version if you specify a minor version.");
803 return false;
804 }
805
806 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE &&
807 platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
808 {
809 val->setError(EGL_BAD_ATTRIBUTE,
810 message: "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a "
811 "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.");
812 return false;
813 }
814
815 if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
816 {
817 val->setError(EGL_BAD_ATTRIBUTE,
818 message: "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE "
819 "requires a device type of "
820 "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.");
821 return false;
822 }
823
824 if (enableD3D11on12)
825 {
826 if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
827 {
828 val->setError(EGL_BAD_ATTRIBUTE,
829 message: "EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE "
830 "requires a platform type of "
831 "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.");
832 return false;
833 }
834
835 if (deviceType.valid() && deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE &&
836 deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE)
837 {
838 val->setError(EGL_BAD_ATTRIBUTE,
839 message: "EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE requires a device "
840 "type of EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE "
841 "or EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE");
842 return false;
843 }
844 }
845
846 if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
847 {
848 val->setError(EGL_BAD_ATTRIBUTE,
849 message: "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a "
850 "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.");
851 return false;
852 }
853
854 if (luidSpecified)
855 {
856 if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
857 {
858 val->setError(EGL_BAD_ATTRIBUTE,
859 message: "EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE and "
860 "EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE "
861 "require a platform type of "
862 "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.");
863 return false;
864 }
865
866 if (attribMap.get(EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE, defaultValue: 0) == 0 &&
867 attribMap.get(EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE, defaultValue: 0) == 0)
868 {
869 val->setError(EGL_BAD_ATTRIBUTE,
870 message: "If either EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE "
871 "and/or EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE are "
872 "specified, at least one must non-zero.");
873 return false;
874 }
875 }
876
877 if (deviceIdSpecified)
878 {
879 if (attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, defaultValue: 0) == 0 &&
880 attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, defaultValue: 0) == 0)
881 {
882 val->setError(EGL_BAD_ATTRIBUTE,
883 message: "If either EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE "
884 "and/or EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE are "
885 "specified, at least one must non-zero.");
886 return false;
887 }
888 }
889
890 if (deviceType.valid())
891 {
892 switch (deviceType.value())
893 {
894 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE:
895 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE:
896 if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
897 platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
898 {
899 val->setError(EGL_BAD_ATTRIBUTE,
900 message: "This device type requires a "
901 "platform type of EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or "
902 "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE.");
903 return false;
904 }
905 break;
906
907 case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE:
908 if (platformType != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
909 {
910 val->setError(EGL_BAD_ATTRIBUTE,
911 message: "This device type requires a "
912 "platform type of EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE.");
913 return false;
914 }
915 break;
916
917 default:
918 break;
919 }
920 }
921
922 if (platformType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
923 {
924 if ((majorVersion.valid() && majorVersion.value() != 1) ||
925 (minorVersion.valid() && minorVersion.value() != 0))
926 {
927 val->setError(EGL_BAD_ATTRIBUTE,
928 message: "EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE currently "
929 "only supports Vulkan 1.0.");
930 return false;
931 }
932 }
933
934 if (eglHandle.valid() && platformType != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE &&
935 platformType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
936 {
937 val->setError(EGL_BAD_ATTRIBUTE,
938 message: "EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE requires a "
939 "device type of EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE.");
940 return false;
941 }
942 }
943 else
944 {
945 const Device *eglDevice = static_cast<const Device *>(native_display);
946 if (eglDevice == nullptr || !Device::IsValidDevice(device: eglDevice))
947 {
948 val->setError(EGL_BAD_ATTRIBUTE,
949 message: "native_display should be a valid EGL device if "
950 "platform equals EGL_PLATFORM_DEVICE_EXT");
951 return false;
952 }
953 }
954
955 if (attribMap.contains(EGL_POWER_PREFERENCE_ANGLE))
956 {
957 if (!clientExtensions.displayPowerPreferenceANGLE)
958 {
959 val->setError(EGL_BAD_ATTRIBUTE,
960 message: "Attribute EGL_POWER_PREFERENCE_ANGLE "
961 "requires EGL_ANGLE_display_power_preference.");
962 return false;
963 }
964 EGLAttrib value = attribMap.get(EGL_POWER_PREFERENCE_ANGLE, defaultValue: 0);
965 if (value != EGL_LOW_POWER_ANGLE && value != EGL_HIGH_POWER_ANGLE)
966 {
967 val->setError(EGL_BAD_ATTRIBUTE,
968 message: "EGL_POWER_PREFERENCE_ANGLE must be "
969 "either EGL_LOW_POWER_ANGLE or EGL_HIGH_POWER_ANGLE.");
970 return false;
971 }
972 }
973
974 if (attribMap.contains(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE))
975 {
976 if (!clientExtensions.featureControlANGLE)
977 {
978 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_ANGLE_feature_control is not supported");
979 return false;
980 }
981 else if (attribMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, defaultValue: 0) == 0)
982 {
983 val->setError(EGL_BAD_ATTRIBUTE,
984 message: "EGL_FEATURE_OVERRIDES_ENABLED_ANGLE must be a valid pointer");
985 return false;
986 }
987 }
988 if (attribMap.contains(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE))
989 {
990 if (!clientExtensions.featureControlANGLE)
991 {
992 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_ANGLE_feature_control is not supported");
993 return false;
994 }
995 else if (attribMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, defaultValue: 0) == 0)
996 {
997 val->setError(EGL_BAD_ATTRIBUTE,
998 message: "EGL_FEATURE_OVERRIDES_DISABLED_ANGLE must be a valid pointer");
999 return false;
1000 }
1001 }
1002
1003 return true;
1004}
1005
1006bool ValidateStream(const ValidationContext *val, const Display *display, const Stream *stream)
1007{
1008 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
1009
1010 const DisplayExtensions &displayExtensions = display->getExtensions();
1011 if (!displayExtensions.stream)
1012 {
1013 val->setError(EGL_BAD_ACCESS, message: "Stream extension not active");
1014 return false;
1015 }
1016
1017 if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
1018 {
1019 val->setError(EGL_BAD_STREAM_KHR, message: "Invalid stream");
1020 return false;
1021 }
1022
1023 return true;
1024}
1025
1026bool ValidateLabeledObject(const ValidationContext *val,
1027 const Display *display,
1028 ObjectType objectType,
1029 EGLObjectKHR object,
1030 const LabeledObject **outLabeledObject)
1031{
1032 switch (objectType)
1033 {
1034 case ObjectType::Context:
1035 {
1036 EGLContext context = static_cast<EGLContext>(object);
1037 gl::ContextID contextID = PackParam<gl::ContextID>(from: context);
1038 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
1039 *outLabeledObject = display->getContext(contextID);
1040 break;
1041 }
1042
1043 case ObjectType::Display:
1044 {
1045 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
1046 if (display != object)
1047 {
1048 if (val)
1049 {
1050 val->setError(EGL_BAD_PARAMETER,
1051 message: "when object type is EGL_OBJECT_DISPLAY_KHR, the "
1052 "object must be the same as the display.");
1053 }
1054 return false;
1055 }
1056
1057 *outLabeledObject = static_cast<Display *>(object);
1058 break;
1059 }
1060
1061 case ObjectType::Image:
1062 {
1063 EGLImage image = static_cast<EGLImage>(object);
1064 ImageID imageID = PackParam<ImageID>(from: image);
1065 ANGLE_VALIDATION_TRY(ValidateImage(val, display, imageID));
1066 *outLabeledObject = display->getImage(imageID);
1067 break;
1068 }
1069
1070 case ObjectType::Stream:
1071 {
1072 Stream *stream = static_cast<Stream *>(object);
1073 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
1074 *outLabeledObject = stream;
1075 break;
1076 }
1077
1078 case ObjectType::Surface:
1079 {
1080 EGLSurface surface = static_cast<EGLSurface>(object);
1081 SurfaceID surfaceID = PackParam<SurfaceID>(from: surface);
1082 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
1083 *outLabeledObject = display->getSurface(surfaceID);
1084 break;
1085 }
1086
1087 case ObjectType::Sync:
1088 {
1089 Sync *sync = static_cast<Sync *>(object);
1090 SyncID syncID = PackParam<SyncID>(from: sync);
1091 ANGLE_VALIDATION_TRY(ValidateSync(val, display, syncID));
1092 *outLabeledObject = sync;
1093 break;
1094 }
1095
1096 case ObjectType::Thread:
1097 {
1098 ASSERT(val);
1099 *outLabeledObject = val->eglThread;
1100 break;
1101 }
1102
1103 default:
1104 if (val)
1105 {
1106 val->setError(EGL_BAD_PARAMETER, message: "unknown object type.");
1107 }
1108 return false;
1109 }
1110
1111 return true;
1112}
1113
1114bool ValidateLabeledObject(const ValidationContext *val,
1115 Display *display,
1116 ObjectType objectType,
1117 EGLObjectKHR object,
1118 LabeledObject **outLabeledObject)
1119{
1120 return ValidateLabeledObject(val, display: const_cast<const Display *>(display), objectType, object,
1121 outLabeledObject: const_cast<const LabeledObject **>(outLabeledObject));
1122}
1123
1124// This is a common sub-check of Display status that's shared by multiple functions
1125bool ValidateDisplayPointer(const ValidationContext *val, const Display *display)
1126{
1127 if (display == EGL_NO_DISPLAY)
1128 {
1129 if (val)
1130 {
1131 val->setError(EGL_BAD_DISPLAY, message: "display is EGL_NO_DISPLAY.");
1132 }
1133 return false;
1134 }
1135
1136 if (!Display::isValidDisplay(display))
1137 {
1138 if (val)
1139 {
1140 val->setError(EGL_BAD_DISPLAY, message: "display is not a valid display: 0x%p", display);
1141 }
1142 return false;
1143 }
1144
1145 return true;
1146}
1147
1148bool ValidCompositorTimingName(CompositorTiming name)
1149{
1150 switch (name)
1151 {
1152 case CompositorTiming::CompositeDeadline:
1153 case CompositorTiming::CompositInterval:
1154 case CompositorTiming::CompositToPresentLatency:
1155 return true;
1156
1157 default:
1158 return false;
1159 }
1160}
1161
1162bool ValidTimestampType(Timestamp timestamp)
1163{
1164 switch (timestamp)
1165 {
1166 case Timestamp::RequestedPresentTime:
1167 case Timestamp::RenderingCompleteTime:
1168 case Timestamp::CompositionLatchTime:
1169 case Timestamp::FirstCompositionStartTime:
1170 case Timestamp::LastCompositionStartTime:
1171 case Timestamp::FirstCompositionGPUFinishedTime:
1172 case Timestamp::DisplayPresentTime:
1173 case Timestamp::DequeueReadyTime:
1174 case Timestamp::ReadsDoneTime:
1175 return true;
1176
1177 default:
1178 return false;
1179 }
1180}
1181
1182bool ValidateCompatibleSurface(const ValidationContext *val,
1183 const Display *display,
1184 const gl::Context *context,
1185 const Surface *surface)
1186{
1187 const Config *contextConfig = context->getConfig();
1188 const Config *surfaceConfig = surface->getConfig();
1189
1190 if (context->getClientType() != EGL_OPENGL_API)
1191 {
1192 // Surface compatible with client API - only OPENGL_ES supported
1193 switch (context->getClientMajorVersion())
1194 {
1195 case 1:
1196 if (!(surfaceConfig->renderableType & EGL_OPENGL_ES_BIT))
1197 {
1198 val->setError(EGL_BAD_MATCH, message: "Surface not compatible with OpenGL ES 1.x.");
1199 return false;
1200 }
1201 break;
1202 case 2:
1203 if (!(surfaceConfig->renderableType & EGL_OPENGL_ES2_BIT))
1204 {
1205 val->setError(EGL_BAD_MATCH, message: "Surface not compatible with OpenGL ES 2.x.");
1206 return false;
1207 }
1208 break;
1209 case 3:
1210 if (!(surfaceConfig->renderableType & (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT)))
1211 {
1212 val->setError(EGL_BAD_MATCH, message: "Surface not compatible with OpenGL ES 3.x.");
1213 return false;
1214 }
1215 break;
1216 default:
1217 val->setError(EGL_BAD_MATCH, message: "Surface not compatible with Context API.");
1218 return false;
1219 }
1220 }
1221 else
1222 {
1223 if (!(surfaceConfig->renderableType & EGL_OPENGL_BIT))
1224 {
1225 val->setError(EGL_BAD_MATCH, message: "Surface not compatible with OpenGL Desktop.");
1226 return false;
1227 }
1228 }
1229
1230 // EGL KHR no config context
1231 if (context->getConfig() == EGL_NO_CONFIG_KHR)
1232 {
1233 const DisplayExtensions &displayExtensions = display->getExtensions();
1234 if (displayExtensions.noConfigContext)
1235 {
1236 return true;
1237 }
1238 val->setError(EGL_BAD_MATCH, message: "Context with no config is not supported.");
1239 return false;
1240 }
1241
1242 // Config compatibility is defined in section 2.2 of the EGL 1.5 spec
1243
1244 bool colorBufferCompat = surfaceConfig->colorBufferType == contextConfig->colorBufferType;
1245 if (!colorBufferCompat)
1246 {
1247 val->setError(EGL_BAD_MATCH, message: "Color buffer types are not compatible.");
1248 return false;
1249 }
1250
1251 bool colorCompat = surfaceConfig->redSize == contextConfig->redSize &&
1252 surfaceConfig->greenSize == contextConfig->greenSize &&
1253 surfaceConfig->blueSize == contextConfig->blueSize &&
1254 surfaceConfig->alphaSize == contextConfig->alphaSize &&
1255 surfaceConfig->luminanceSize == contextConfig->luminanceSize;
1256 if (!colorCompat)
1257 {
1258 val->setError(EGL_BAD_MATCH, message: "Color buffer sizes are not compatible.");
1259 return false;
1260 }
1261
1262 bool componentTypeCompat =
1263 surfaceConfig->colorComponentType == contextConfig->colorComponentType;
1264 if (!componentTypeCompat)
1265 {
1266 val->setError(EGL_BAD_MATCH, message: "Color buffer component types are not compatible.");
1267 return false;
1268 }
1269
1270 bool dsCompat = surfaceConfig->depthSize == contextConfig->depthSize &&
1271 surfaceConfig->stencilSize == contextConfig->stencilSize;
1272 if (!dsCompat)
1273 {
1274 val->setError(EGL_BAD_MATCH, message: "Depth-stencil buffer types are not compatible.");
1275 return false;
1276 }
1277
1278 bool surfaceTypeCompat = (surfaceConfig->surfaceType & contextConfig->surfaceType) != 0;
1279 if (!surfaceTypeCompat)
1280 {
1281 val->setError(EGL_BAD_MATCH, message: "Surface type is not compatible.");
1282 return false;
1283 }
1284
1285 return true;
1286}
1287
1288bool ValidateCreateSyncBase(const ValidationContext *val,
1289 const Display *display,
1290 EGLenum type,
1291 const AttributeMap &attribs,
1292 bool isExt)
1293{
1294 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
1295
1296 attribs.initializeWithoutValidation();
1297
1298 gl::Context *currentContext = val->eglThread->getContext();
1299 egl::Display *currentDisplay = currentContext ? currentContext->getDisplay() : nullptr;
1300
1301 switch (type)
1302 {
1303 case EGL_SYNC_FENCE_KHR:
1304 if (!attribs.isEmpty())
1305 {
1306 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
1307 return false;
1308 }
1309
1310 if (!display->getExtensions().fenceSync)
1311 {
1312 val->setError(EGL_BAD_MATCH, message: "EGL_KHR_fence_sync extension is not available");
1313 return false;
1314 }
1315
1316 if (display != currentDisplay)
1317 {
1318 val->setError(EGL_BAD_MATCH,
1319 message: "CreateSync can only be called on the current display");
1320 return false;
1321 }
1322
1323 ANGLE_VALIDATION_TRY(ValidateContext(val, currentDisplay, currentContext->id()));
1324
1325 if (!currentContext->getExtensions().EGLSyncOES)
1326 {
1327 val->setError(EGL_BAD_MATCH,
1328 message: "EGL_SYNC_FENCE_KHR cannot be used without "
1329 "GL_OES_EGL_sync support.");
1330 return false;
1331 }
1332 break;
1333
1334 case EGL_SYNC_NATIVE_FENCE_ANDROID:
1335 if (!display->getExtensions().fenceSync)
1336 {
1337 val->setError(EGL_BAD_MATCH, message: "EGL_KHR_fence_sync extension is not available");
1338 return false;
1339 }
1340
1341 if (!display->getExtensions().nativeFenceSyncANDROID)
1342 {
1343 val->setError(EGL_BAD_DISPLAY,
1344 message: "EGL_ANDROID_native_fence_sync extension is not available.");
1345 return false;
1346 }
1347
1348 if (display != currentDisplay)
1349 {
1350 val->setError(EGL_BAD_MATCH,
1351 message: "CreateSync can only be called on the current display");
1352 return false;
1353 }
1354
1355 ANGLE_VALIDATION_TRY(ValidateContext(val, currentDisplay, currentContext->id()));
1356
1357 if (!currentContext->getExtensions().EGLSyncOES)
1358 {
1359 val->setError(EGL_BAD_MATCH,
1360 message: "EGL_SYNC_FENCE_KHR cannot be used without "
1361 "GL_OES_EGL_sync support.");
1362 return false;
1363 }
1364
1365 for (const auto &attributeIter : attribs)
1366 {
1367 EGLAttrib attribute = attributeIter.first;
1368
1369 switch (attribute)
1370 {
1371 case EGL_SYNC_NATIVE_FENCE_FD_ANDROID:
1372 break;
1373
1374 default:
1375 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
1376 return false;
1377 }
1378 }
1379 break;
1380
1381 case EGL_SYNC_REUSABLE_KHR:
1382 if (!attribs.isEmpty())
1383 {
1384 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
1385 return false;
1386 }
1387
1388 if (!display->getExtensions().reusableSyncKHR)
1389 {
1390 val->setError(EGL_BAD_MATCH, message: "EGL_KHR_reusable_sync extension is not available.");
1391 return false;
1392 }
1393 break;
1394
1395 case EGL_SYNC_METAL_SHARED_EVENT_ANGLE:
1396 if (!display->getExtensions().fenceSync)
1397 {
1398 val->setError(EGL_BAD_MATCH, message: "EGL_KHR_fence_sync extension is not available");
1399 return false;
1400 }
1401
1402 if (!display->getExtensions().mtlSyncSharedEventANGLE)
1403 {
1404 val->setError(EGL_BAD_DISPLAY,
1405 message: "EGL_ANGLE_metal_shared_event_sync is not available");
1406 return false;
1407 }
1408
1409 if (display != currentDisplay)
1410 {
1411 val->setError(EGL_BAD_MATCH,
1412 message: "CreateSync can only be called on the current display");
1413 return false;
1414 }
1415
1416 ANGLE_VALIDATION_TRY(ValidateContext(val, currentDisplay, currentContext->id()));
1417
1418 // This should be implied by exposing EGL_KHR_fence_sync
1419 ASSERT(currentContext->getExtensions().EGLSyncOES);
1420
1421 for (const auto &attributeIter : attribs)
1422 {
1423 EGLAttrib attribute = attributeIter.first;
1424 EGLAttrib value = attributeIter.second;
1425
1426 switch (attribute)
1427 {
1428 case EGL_SYNC_CONDITION:
1429 if (type != EGL_SYNC_METAL_SHARED_EVENT_ANGLE ||
1430 (value != EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR &&
1431 value != EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE))
1432 {
1433 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
1434 }
1435 break;
1436
1437 case EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE:
1438 if (!value)
1439 {
1440 val->setError(EGL_BAD_ATTRIBUTE,
1441 message: "EGL_SYNC_METAL_SHARED_EVENT_ANGLE can't be NULL");
1442 return false;
1443 }
1444 break;
1445
1446 case EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE:
1447 case EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE:
1448 break;
1449
1450 default:
1451 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
1452 return false;
1453 }
1454 }
1455 break;
1456
1457 default:
1458 if (isExt)
1459 {
1460 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid type parameter");
1461 return false;
1462 }
1463 else
1464 {
1465 val->setError(EGL_BAD_PARAMETER, message: "Invalid type parameter");
1466 return false;
1467 }
1468 }
1469
1470 return true;
1471}
1472
1473bool ValidateGetSyncAttribBase(const ValidationContext *val,
1474 const Display *display,
1475 SyncID sync,
1476 EGLint attribute)
1477{
1478 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
1479
1480 const Sync *syncObj = display->getSync(syncID: sync);
1481
1482 switch (attribute)
1483 {
1484 case EGL_SYNC_CONDITION_KHR:
1485 switch (syncObj->getType())
1486 {
1487 case EGL_SYNC_FENCE_KHR:
1488 case EGL_SYNC_NATIVE_FENCE_ANDROID:
1489 case EGL_SYNC_METAL_SHARED_EVENT_ANGLE:
1490 break;
1491
1492 default:
1493 val->setError(EGL_BAD_ATTRIBUTE,
1494 message: "EGL_SYNC_CONDITION_KHR is not valid for this sync type.");
1495 return false;
1496 }
1497 break;
1498
1499 // The following attributes are accepted by all types
1500 case EGL_SYNC_TYPE_KHR:
1501 case EGL_SYNC_STATUS_KHR:
1502 break;
1503
1504 default:
1505 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
1506 return false;
1507 }
1508
1509 return true;
1510}
1511
1512bool ValidateQueryDisplayAttribBase(const ValidationContext *val,
1513 const Display *display,
1514 const EGLint attribute)
1515{
1516 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
1517
1518 switch (attribute)
1519 {
1520 case EGL_DEVICE_EXT:
1521 if (!Display::GetClientExtensions().deviceQueryEXT)
1522 {
1523 val->setError(EGL_BAD_DISPLAY, message: "EGL_EXT_device_query extension is not available.");
1524 return false;
1525 }
1526 break;
1527
1528 case EGL_FEATURE_COUNT_ANGLE:
1529 if (!Display::GetClientExtensions().featureControlANGLE)
1530 {
1531 val->setError(EGL_BAD_DISPLAY,
1532 message: "EGL_ANGLE_feature_control extension is not available.");
1533 return false;
1534 }
1535 break;
1536
1537 default:
1538 val->setError(EGL_BAD_ATTRIBUTE, message: "attribute is not valid.");
1539 return false;
1540 }
1541
1542 return true;
1543}
1544
1545bool ValidateCreateContextAttribute(const ValidationContext *val,
1546 const Display *display,
1547 EGLAttrib attribute)
1548{
1549 switch (attribute)
1550 {
1551 case EGL_CONTEXT_CLIENT_VERSION:
1552 case EGL_CONTEXT_MINOR_VERSION:
1553 case EGL_CONTEXT_FLAGS_KHR:
1554 case EGL_CONTEXT_OPENGL_DEBUG:
1555 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
1556 break;
1557
1558 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
1559 if (val->eglThread->getAPI() != EGL_OPENGL_API)
1560 {
1561 // Only valid for OpenGL (non-ES) contexts
1562 val->setError(EGL_BAD_ATTRIBUTE, message: "OpenGL profile mask requires an OpenGL context.");
1563 return false;
1564 }
1565 break;
1566
1567 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
1568 if (!display->getExtensions().createContextRobustness)
1569 {
1570 val->setError(EGL_BAD_ATTRIBUTE);
1571 return false;
1572 }
1573 break;
1574
1575 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
1576 if (!display->getExtensions().createContextRobustness)
1577 {
1578 val->setError(EGL_BAD_ATTRIBUTE);
1579 return false;
1580 }
1581 break;
1582
1583 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY:
1584 {
1585 // We either need to have -
1586 // 1. EGL 1.5 which added support for this as part of core spec
1587 // 2. EGL_KHR_create_context extension which requires EGL 1.4
1588 constexpr EGLint kRequiredMajorVersion = 1;
1589 constexpr EGLint kRequiredMinorVersion = 5;
1590 if ((kEglMajorVersion < kRequiredMajorVersion ||
1591 kEglMinorVersion < kRequiredMinorVersion) &&
1592 !display->getExtensions().createContext)
1593 {
1594 val->setError(EGL_BAD_ATTRIBUTE);
1595 return false;
1596 }
1597 break;
1598 }
1599
1600 case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
1601 if (!display->getExtensions().createContextNoError)
1602 {
1603 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid Context attribute.");
1604 return false;
1605 }
1606 break;
1607
1608 case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE:
1609 if (!display->getExtensions().createContextWebGLCompatibility)
1610 {
1611 val->setError(EGL_BAD_ATTRIBUTE,
1612 message: "Attribute "
1613 "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires "
1614 "EGL_ANGLE_create_context_webgl_compatibility.");
1615 return false;
1616 }
1617 break;
1618
1619 case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM:
1620 if (!display->getExtensions().createContextBindGeneratesResource)
1621 {
1622 val->setError(EGL_BAD_ATTRIBUTE,
1623 message: "Attribute EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM requires "
1624 "EGL_CHROMIUM_create_context_bind_generates_resource.");
1625 return false;
1626 }
1627 break;
1628
1629 case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE:
1630 if (!display->getExtensions().displayTextureShareGroup)
1631 {
1632 val->setError(EGL_BAD_ATTRIBUTE,
1633 message: "Attribute "
1634 "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE requires "
1635 "EGL_ANGLE_display_texture_share_group.");
1636 return false;
1637 }
1638 break;
1639
1640 case EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE:
1641 if (!display->getExtensions().displayTextureShareGroup)
1642 {
1643 val->setError(EGL_BAD_ATTRIBUTE,
1644 message: "Attribute "
1645 "EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE requires "
1646 "EGL_ANGLE_display_semaphore_share_group.");
1647 return false;
1648 }
1649 break;
1650
1651 case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE:
1652 if (!display->getExtensions().createContextClientArrays)
1653 {
1654 val->setError(EGL_BAD_ATTRIBUTE,
1655 message: "Attribute EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE requires "
1656 "EGL_ANGLE_create_context_client_arrays.");
1657 return false;
1658 }
1659 break;
1660
1661 case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE:
1662 if (!display->getExtensions().programCacheControlANGLE)
1663 {
1664 val->setError(EGL_BAD_ATTRIBUTE,
1665 message: "Attribute EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE "
1666 "requires EGL_ANGLE_program_cache_control.");
1667 return false;
1668 }
1669 break;
1670
1671 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
1672 if (!display->getExtensions().robustResourceInitializationANGLE)
1673 {
1674 val->setError(EGL_BAD_ATTRIBUTE,
1675 message: "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
1676 "requires EGL_ANGLE_robust_resource_initialization.");
1677 return false;
1678 }
1679 break;
1680
1681 case EGL_EXTENSIONS_ENABLED_ANGLE:
1682 if (!display->getExtensions().createContextExtensionsEnabled)
1683 {
1684 val->setError(EGL_BAD_ATTRIBUTE,
1685 message: "Attribute EGL_EXTENSIONS_ENABLED_ANGLE "
1686 "requires EGL_ANGLE_create_context_extensions_enabled.");
1687 return false;
1688 }
1689 break;
1690
1691 case EGL_POWER_PREFERENCE_ANGLE:
1692 if (!display->getExtensions().powerPreference)
1693 {
1694 val->setError(EGL_BAD_ATTRIBUTE,
1695 message: "Attribute EGL_POWER_PREFERENCE_ANGLE "
1696 "requires EGL_ANGLE_power_preference.");
1697 return false;
1698 }
1699 break;
1700
1701 case EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE:
1702 if (!display->getExtensions().createContextBackwardsCompatible)
1703 {
1704 val->setError(EGL_BAD_ATTRIBUTE,
1705 message: "Attribute EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE "
1706 "requires EGL_ANGLE_create_context_backwards_compatible.");
1707 return false;
1708 }
1709 break;
1710
1711 case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
1712 if (!display->getExtensions().contextPriority)
1713 {
1714 val->setError(EGL_BAD_ATTRIBUTE,
1715 message: "Attribute EGL_CONTEXT_PRIORITY_LEVEL_IMG requires "
1716 "extension EGL_IMG_context_priority.");
1717 return false;
1718 }
1719 break;
1720
1721 case EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV:
1722 if (!display->getExtensions().robustnessVideoMemoryPurgeNV)
1723 {
1724 val->setError(EGL_BAD_ATTRIBUTE,
1725 message: "Attribute EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV requires "
1726 "extension EGL_NV_robustness_video_memory_purge.");
1727 return false;
1728 }
1729 break;
1730
1731 case EGL_EXTERNAL_CONTEXT_ANGLE:
1732 if (!display->getExtensions().externalContextAndSurface)
1733 {
1734 val->setError(EGL_BAD_ATTRIBUTE,
1735 message: "Attribute "
1736 "EGL_EXTERNAL_CONTEXT_ANGLE requires "
1737 "EGL_ANGLE_external_context_and_surface.");
1738 return false;
1739 }
1740 break;
1741 case EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE:
1742 if (!display->getExtensions().externalContextAndSurface)
1743 {
1744 val->setError(EGL_BAD_ATTRIBUTE,
1745 message: "Attribute "
1746 "EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE requires "
1747 "EGL_ANGLE_external_context_and_surface.");
1748 return false;
1749 }
1750 break;
1751
1752 case EGL_PROTECTED_CONTENT_EXT:
1753 if (!display->getExtensions().protectedContentEXT)
1754 {
1755 val->setError(EGL_BAD_ATTRIBUTE,
1756 message: "Attribute EGL_PROTECTED_CONTEXT_EXT requires "
1757 "extension EGL_EXT_protected_content.");
1758 return false;
1759 }
1760 break;
1761
1762 case EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE:
1763 if (!display->getExtensions().contextVirtualizationANGLE)
1764 {
1765 val->setError(EGL_BAD_ATTRIBUTE,
1766 message: "Attribute EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE requires "
1767 "extension EGL_ANGLE_context_virtualization.");
1768 return false;
1769 }
1770 break;
1771
1772 case EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE:
1773 if (!display->getExtensions().metalCreateContextOwnershipIdentityANGLE)
1774 {
1775 val->setError(EGL_BAD_ATTRIBUTE,
1776 message: "Attribute EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE requires "
1777 "EGL_ANGLE_metal_create_context_ownership_identity.");
1778 }
1779 break;
1780
1781 default:
1782 val->setError(EGL_BAD_ATTRIBUTE, message: "Unknown attribute: 0x%04" PRIxPTR "X", attribute);
1783 return false;
1784 }
1785
1786 return true;
1787}
1788
1789bool ValidateCreateContextAttributeValue(const ValidationContext *val,
1790 const Display *display,
1791 const gl::Context *shareContext,
1792 EGLAttrib attribute,
1793 EGLAttrib value)
1794{
1795 switch (attribute)
1796 {
1797 case EGL_CONTEXT_CLIENT_VERSION:
1798 case EGL_CONTEXT_MINOR_VERSION:
1799 case EGL_CONTEXT_OPENGL_DEBUG:
1800 case EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE:
1801 break;
1802
1803 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
1804 {
1805 constexpr EGLint kValidProfileMaskFlags =
1806 (EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT |
1807 EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
1808 if ((value & ~kValidProfileMaskFlags) != 0)
1809 {
1810 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid OpenGL profile mask.");
1811 return false;
1812 }
1813 break;
1814 }
1815
1816 case EGL_CONTEXT_FLAGS_KHR:
1817 {
1818 // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES
1819 constexpr EGLint kValidContextFlags =
1820 (EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
1821 if ((value & ~kValidContextFlags) != 0)
1822 {
1823 val->setError(EGL_BAD_ATTRIBUTE);
1824 return false;
1825 }
1826 break;
1827 }
1828
1829 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
1830 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
1831 if (value != EGL_TRUE && value != EGL_FALSE)
1832 {
1833 val->setError(EGL_BAD_ATTRIBUTE);
1834 return false;
1835 }
1836 break;
1837
1838 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
1839 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY:
1840 if (value != EGL_LOSE_CONTEXT_ON_RESET_EXT && value != EGL_NO_RESET_NOTIFICATION_EXT)
1841 {
1842 val->setError(EGL_BAD_ATTRIBUTE);
1843 return false;
1844 }
1845
1846 if (shareContext && shareContext->isResetNotificationEnabled() !=
1847 (value == EGL_LOSE_CONTEXT_ON_RESET_EXT))
1848 {
1849 val->setError(EGL_BAD_MATCH);
1850 return false;
1851 }
1852 break;
1853
1854 case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
1855 if (value != EGL_TRUE && value != EGL_FALSE)
1856 {
1857 val->setError(EGL_BAD_ATTRIBUTE, message: "Attribute must be EGL_TRUE or EGL_FALSE.");
1858 return false;
1859 }
1860 break;
1861
1862 case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE:
1863 if (value != EGL_TRUE && value != EGL_FALSE)
1864 {
1865 val->setError(EGL_BAD_ATTRIBUTE,
1866 message: "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be "
1867 "EGL_TRUE or EGL_FALSE.");
1868 return false;
1869 }
1870 break;
1871
1872 case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM:
1873 if (value != EGL_TRUE && value != EGL_FALSE)
1874 {
1875 val->setError(EGL_BAD_ATTRIBUTE,
1876 message: "EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM "
1877 "must be EGL_TRUE or EGL_FALSE.");
1878 return false;
1879 }
1880 break;
1881
1882 case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE:
1883 if (value != EGL_TRUE && value != EGL_FALSE)
1884 {
1885 val->setError(EGL_BAD_ATTRIBUTE,
1886 message: "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE must be "
1887 "EGL_TRUE or EGL_FALSE.");
1888 return false;
1889 }
1890 if (shareContext &&
1891 shareContext->usingDisplayTextureShareGroup() != (value == EGL_TRUE))
1892 {
1893 val->setError(EGL_BAD_ATTRIBUTE,
1894 message: "All contexts within a share group must be "
1895 "created with the same value of "
1896 "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE.");
1897 return false;
1898 }
1899 break;
1900
1901 case EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE:
1902 if (value != EGL_TRUE && value != EGL_FALSE)
1903 {
1904 val->setError(EGL_BAD_ATTRIBUTE,
1905 message: "EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE must be "
1906 "EGL_TRUE or EGL_FALSE.");
1907 return false;
1908 }
1909 if (shareContext &&
1910 shareContext->usingDisplaySemaphoreShareGroup() != (value == EGL_TRUE))
1911 {
1912 val->setError(EGL_BAD_ATTRIBUTE,
1913 message: "All contexts within a share group must be "
1914 "created with the same value of "
1915 "EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE.");
1916 return false;
1917 }
1918 break;
1919
1920 case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE:
1921 if (value != EGL_TRUE && value != EGL_FALSE)
1922 {
1923 val->setError(EGL_BAD_ATTRIBUTE,
1924 message: "EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE must "
1925 "be EGL_TRUE or EGL_FALSE.");
1926 return false;
1927 }
1928 break;
1929
1930 case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE:
1931 if (value != EGL_TRUE && value != EGL_FALSE)
1932 {
1933 val->setError(EGL_BAD_ATTRIBUTE,
1934 message: "EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE must "
1935 "be EGL_TRUE or EGL_FALSE.");
1936 return false;
1937 }
1938 break;
1939
1940 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
1941 if (value != EGL_TRUE && value != EGL_FALSE)
1942 {
1943 val->setError(EGL_BAD_ATTRIBUTE,
1944 message: "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
1945 "either EGL_TRUE or EGL_FALSE.");
1946 return false;
1947 }
1948 break;
1949
1950 case EGL_EXTENSIONS_ENABLED_ANGLE:
1951 if (value != EGL_TRUE && value != EGL_FALSE)
1952 {
1953 val->setError(EGL_BAD_ATTRIBUTE,
1954 message: "EGL_EXTENSIONS_ENABLED_ANGLE must be "
1955 "either EGL_TRUE or EGL_FALSE.");
1956 return false;
1957 }
1958 break;
1959
1960 case EGL_POWER_PREFERENCE_ANGLE:
1961 if (value != EGL_LOW_POWER_ANGLE && value != EGL_HIGH_POWER_ANGLE)
1962 {
1963 val->setError(EGL_BAD_ATTRIBUTE,
1964 message: "EGL_POWER_PREFERENCE_ANGLE must be "
1965 "either EGL_LOW_POWER_ANGLE or EGL_HIGH_POWER_ANGLE.");
1966 return false;
1967 }
1968 break;
1969
1970 case EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE:
1971 if (value != EGL_TRUE && value != EGL_FALSE)
1972 {
1973 val->setError(EGL_BAD_ATTRIBUTE,
1974 message: "EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE must be "
1975 "either EGL_TRUE or EGL_FALSE.");
1976 return false;
1977 }
1978 break;
1979
1980 case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
1981 switch (value)
1982 {
1983 case EGL_CONTEXT_PRIORITY_LOW_IMG:
1984 case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
1985 case EGL_CONTEXT_PRIORITY_HIGH_IMG:
1986 break;
1987 default:
1988 val->setError(EGL_BAD_ATTRIBUTE,
1989 message: "Attribute EGL_CONTEXT_PRIORITY_LEVEL_IMG "
1990 "must be one of: EGL_CONTEXT_PRIORITY_LOW_IMG, "
1991 "EGL_CONTEXT_PRIORITY_MEDIUM_IMG, or "
1992 "EGL_CONTEXT_PRIORITY_HIGH_IMG.");
1993 return false;
1994 }
1995 break;
1996
1997 case EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV:
1998 if (value != EGL_TRUE && value != EGL_FALSE)
1999 {
2000 val->setError(EGL_BAD_ATTRIBUTE,
2001 message: "EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV must "
2002 "be either EGL_TRUE or EGL_FALSE.");
2003 return false;
2004 }
2005 break;
2006
2007 case EGL_EXTERNAL_CONTEXT_ANGLE:
2008 if (value != EGL_TRUE && value != EGL_FALSE)
2009 {
2010 val->setError(EGL_BAD_ATTRIBUTE,
2011 message: "EGL_EXTERNAL_CONTEXT_ANGLE must "
2012 "be either EGL_TRUE or EGL_FALSE.");
2013 return false;
2014 }
2015 if (shareContext && (value == EGL_TRUE))
2016 {
2017 val->setError(
2018 EGL_BAD_ATTRIBUTE,
2019 message: "EGL_EXTERNAL_CONTEXT_ANGLE doesn't allow creating with sharedContext.");
2020 return false;
2021 }
2022 break;
2023 case EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE:
2024 if (value != EGL_TRUE && value != EGL_FALSE)
2025 {
2026 val->setError(EGL_BAD_ATTRIBUTE,
2027 message: "EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE must "
2028 "be either EGL_TRUE or EGL_FALSE.");
2029 return false;
2030 }
2031 break;
2032
2033 case EGL_PROTECTED_CONTENT_EXT:
2034 if (value != EGL_TRUE && value != EGL_FALSE)
2035 {
2036 val->setError(EGL_BAD_ATTRIBUTE,
2037 message: "EGL_PROTECTED_CONTENT_EXT must "
2038 "be either EGL_TRUE or EGL_FALSE.");
2039 return false;
2040 }
2041 break;
2042
2043 case EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE:
2044 if (value == 0)
2045 {
2046 val->setError(EGL_BAD_ATTRIBUTE,
2047 message: "EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE must"
2048 "be non-zero.");
2049 return false;
2050 }
2051 break;
2052
2053 default:
2054 UNREACHABLE();
2055 return false;
2056 }
2057
2058 return true;
2059}
2060
2061bool ValidateCreatePbufferSurfaceAttribute(const ValidationContext *val,
2062 const Display *display,
2063 EGLAttrib attribute)
2064{
2065 const DisplayExtensions &displayExtensions = display->getExtensions();
2066
2067 switch (attribute)
2068 {
2069 case EGL_WIDTH:
2070 case EGL_HEIGHT:
2071 case EGL_LARGEST_PBUFFER:
2072 case EGL_TEXTURE_FORMAT:
2073 case EGL_TEXTURE_TARGET:
2074 case EGL_MIPMAP_TEXTURE:
2075 case EGL_VG_COLORSPACE:
2076 case EGL_GL_COLORSPACE:
2077 case EGL_VG_ALPHA_FORMAT:
2078 break;
2079
2080 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
2081 if (!displayExtensions.robustResourceInitializationANGLE)
2082 {
2083 val->setError(EGL_BAD_ATTRIBUTE,
2084 message: "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
2085 "requires EGL_ANGLE_robust_resource_initialization.");
2086 return false;
2087 }
2088 break;
2089
2090 case EGL_PROTECTED_CONTENT_EXT:
2091 if (!displayExtensions.protectedContentEXT)
2092 {
2093 val->setError(EGL_BAD_ATTRIBUTE,
2094 message: "Attribute EGL_PROTECTED_CONTEXT_EXT requires "
2095 "extension EGL_EXT_protected_content.");
2096 return false;
2097 }
2098 break;
2099
2100 default:
2101 val->setError(EGL_BAD_ATTRIBUTE);
2102 return false;
2103 }
2104
2105 return true;
2106}
2107
2108bool ValidateCreatePbufferSurfaceAttributeValue(const ValidationContext *val,
2109 const Display *display,
2110 EGLAttrib attribute,
2111 EGLAttrib value)
2112{
2113 const DisplayExtensions &displayExtensions = display->getExtensions();
2114
2115 switch (attribute)
2116 {
2117 case EGL_WIDTH:
2118 case EGL_HEIGHT:
2119 if (value < 0)
2120 {
2121 val->setError(EGL_BAD_PARAMETER);
2122 return false;
2123 }
2124 break;
2125
2126 case EGL_LARGEST_PBUFFER:
2127 break;
2128
2129 case EGL_TEXTURE_FORMAT:
2130 switch (value)
2131 {
2132 case EGL_NO_TEXTURE:
2133 case EGL_TEXTURE_RGB:
2134 case EGL_TEXTURE_RGBA:
2135 break;
2136 default:
2137 val->setError(EGL_BAD_ATTRIBUTE);
2138 return false;
2139 }
2140 break;
2141
2142 case EGL_TEXTURE_TARGET:
2143 switch (value)
2144 {
2145 case EGL_NO_TEXTURE:
2146 case EGL_TEXTURE_2D:
2147 break;
2148 default:
2149 val->setError(EGL_BAD_ATTRIBUTE);
2150 return false;
2151 }
2152 break;
2153
2154 case EGL_MIPMAP_TEXTURE:
2155 break;
2156
2157 case EGL_VG_COLORSPACE:
2158 break;
2159
2160 case EGL_GL_COLORSPACE:
2161 ANGLE_VALIDATION_TRY(ValidateColorspaceAttribute(val, displayExtensions, value));
2162 break;
2163
2164 case EGL_VG_ALPHA_FORMAT:
2165 break;
2166
2167 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
2168 ASSERT(displayExtensions.robustResourceInitializationANGLE);
2169 if (value != EGL_TRUE && value != EGL_FALSE)
2170 {
2171 val->setError(EGL_BAD_ATTRIBUTE,
2172 message: "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
2173 "either EGL_TRUE or EGL_FALSE.");
2174 return false;
2175 }
2176 break;
2177
2178 case EGL_PROTECTED_CONTENT_EXT:
2179 ASSERT(displayExtensions.protectedContentEXT);
2180 if (value != EGL_TRUE && value != EGL_FALSE)
2181 {
2182 val->setError(EGL_BAD_ATTRIBUTE,
2183 message: "EGL_PROTECTED_CONTENT_EXT must "
2184 "be either EGL_TRUE or EGL_FALSE.");
2185 return false;
2186 }
2187 break;
2188
2189 default:
2190 UNREACHABLE();
2191 return false;
2192 }
2193
2194 return true;
2195}
2196} // anonymous namespace
2197
2198void ValidationContext::setError(EGLint error) const
2199{
2200 eglThread->setError(error, command: entryPoint, object: labeledObject, message: nullptr);
2201}
2202
2203void ValidationContext::setError(EGLint error, const char *message...) const
2204{
2205 ASSERT(message);
2206
2207 constexpr uint32_t kBufferSize = 1000;
2208 char buffer[kBufferSize];
2209
2210 va_list args;
2211 va_start(args, message);
2212 vsnprintf(s: buffer, maxlen: kBufferSize, format: message, arg: args);
2213
2214 eglThread->setError(error, command: entryPoint, object: labeledObject, message: buffer);
2215}
2216
2217bool ValidateDisplay(const ValidationContext *val, const Display *display)
2218{
2219 ANGLE_VALIDATION_TRY(ValidateDisplayPointer(val, display));
2220
2221 if (!display->isInitialized())
2222 {
2223 if (val)
2224 {
2225 val->setError(EGL_NOT_INITIALIZED, message: "display is not initialized.");
2226 }
2227 return false;
2228 }
2229
2230 if (display->isDeviceLost())
2231 {
2232 if (val)
2233 {
2234 val->setError(EGL_CONTEXT_LOST, message: "display had a context loss");
2235 }
2236 return false;
2237 }
2238
2239 return true;
2240}
2241
2242bool ValidateSurface(const ValidationContext *val, const Display *display, SurfaceID surfaceID)
2243{
2244 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2245
2246 if (!display->isValidSurface(surfaceID))
2247 {
2248 if (val)
2249 {
2250 val->setError(EGL_BAD_SURFACE);
2251 }
2252 return false;
2253 }
2254
2255 return true;
2256}
2257
2258bool ValidateConfig(const ValidationContext *val, const Display *display, const Config *config)
2259{
2260 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2261
2262 if (!display->isValidConfig(config))
2263 {
2264 if (val)
2265 {
2266 val->setError(EGL_BAD_CONFIG);
2267 }
2268 return false;
2269 }
2270
2271 return true;
2272}
2273
2274bool ValidateThreadContext(const ValidationContext *val,
2275 const Display *display,
2276 EGLenum noContextError)
2277{
2278 ASSERT(val);
2279 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2280
2281 if (!val->eglThread->getContext())
2282 {
2283 val->setError(error: noContextError, message: "No context is current.");
2284 return false;
2285 }
2286
2287 return true;
2288}
2289
2290bool ValidateContext(const ValidationContext *val, const Display *display, gl::ContextID contextID)
2291{
2292 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2293
2294 if (!display->isValidContext(contextID))
2295 {
2296 if (val)
2297 {
2298 val->setError(EGL_BAD_CONTEXT);
2299 }
2300 return false;
2301 }
2302
2303 return true;
2304}
2305
2306bool ValidateImage(const ValidationContext *val, const Display *display, ImageID imageID)
2307{
2308 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2309
2310 if (!display->isValidImage(imageID))
2311 {
2312 if (val)
2313 {
2314 val->setError(EGL_BAD_PARAMETER, message: "image is not valid.");
2315 }
2316 return false;
2317 }
2318
2319 return true;
2320}
2321
2322bool ValidateDevice(const ValidationContext *val, const Device *device)
2323{
2324 if (device == EGL_NO_DEVICE_EXT)
2325 {
2326 if (val)
2327 {
2328 val->setError(EGL_BAD_ACCESS, message: "device is EGL_NO_DEVICE.");
2329 }
2330 return false;
2331 }
2332
2333 if (!Device::IsValidDevice(device))
2334 {
2335 if (val)
2336 {
2337 val->setError(EGL_BAD_ACCESS, message: "device is not valid.");
2338 }
2339 return false;
2340 }
2341
2342 return true;
2343}
2344
2345bool ValidateSync(const ValidationContext *val, const Display *display, SyncID sync)
2346{
2347 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2348
2349 if (!display->isValidSync(sync))
2350 {
2351 if (val)
2352 {
2353 val->setError(EGL_BAD_PARAMETER, message: "sync object is not valid.");
2354 }
2355 return false;
2356 }
2357
2358 return true;
2359}
2360
2361const Thread *GetThreadIfValid(const Thread *thread)
2362{
2363 // Threads should always be valid
2364 return thread;
2365}
2366
2367const Display *GetDisplayIfValid(const Display *display)
2368{
2369 return ValidateDisplay(val: nullptr, display) ? display : nullptr;
2370}
2371
2372const Surface *GetSurfaceIfValid(const Display *display, SurfaceID surfaceID)
2373{
2374 // display->getSurface() - validates surfaceID
2375 return ValidateDisplay(val: nullptr, display) ? display->getSurface(surfaceID) : nullptr;
2376}
2377
2378const Image *GetImageIfValid(const Display *display, ImageID imageID)
2379{
2380 // display->getImage() - validates imageID
2381 return ValidateDisplay(val: nullptr, display) ? display->getImage(imageID) : nullptr;
2382}
2383
2384const Stream *GetStreamIfValid(const Display *display, const Stream *stream)
2385{
2386 return ValidateStream(val: nullptr, display, stream) ? stream : nullptr;
2387}
2388
2389const gl::Context *GetContextIfValid(const Display *display, gl::ContextID contextID)
2390{
2391 // display->getContext() - validates contextID
2392 return ValidateDisplay(val: nullptr, display) ? display->getContext(contextID) : nullptr;
2393}
2394
2395gl::Context *GetContextIfValid(Display *display, gl::ContextID contextID)
2396{
2397 return ValidateDisplay(val: nullptr, display) ? display->getContext(contextID) : nullptr;
2398}
2399
2400const Device *GetDeviceIfValid(const Device *device)
2401{
2402 return ValidateDevice(val: nullptr, device) ? device : nullptr;
2403}
2404
2405const Sync *GetSyncIfValid(const Display *display, SyncID syncID)
2406{
2407 // display->getSync() - validates syncID
2408 return ValidateDisplay(val: nullptr, display) ? display->getSync(syncID) : nullptr;
2409}
2410
2411const LabeledObject *GetLabeledObjectIfValid(Thread *thread,
2412 const Display *display,
2413 ObjectType objectType,
2414 EGLObjectKHR object)
2415{
2416 if (objectType == ObjectType::Thread)
2417 {
2418 return thread;
2419 }
2420
2421 const LabeledObject *labeledObject = nullptr;
2422 if (ValidateLabeledObject(val: nullptr, display, objectType, object, outLabeledObject: &labeledObject))
2423 {
2424 return labeledObject;
2425 }
2426
2427 return nullptr;
2428}
2429
2430LabeledObject *GetLabeledObjectIfValid(Thread *thread,
2431 Display *display,
2432 ObjectType objectType,
2433 EGLObjectKHR object)
2434{
2435 if (objectType == ObjectType::Thread)
2436 {
2437 return thread;
2438 }
2439
2440 LabeledObject *labeledObject = nullptr;
2441 if (ValidateLabeledObject(val: nullptr, display, objectType, object, outLabeledObject: &labeledObject))
2442 {
2443 return labeledObject;
2444 }
2445
2446 return nullptr;
2447}
2448
2449bool ValidateInitialize(const ValidationContext *val,
2450 const Display *display,
2451 const EGLint *major,
2452 const EGLint *minor)
2453{
2454 return ValidateDisplayPointer(val, display);
2455}
2456
2457bool ValidateTerminate(const ValidationContext *val, const Display *display)
2458{
2459 return ValidateDisplayPointer(val, display);
2460}
2461
2462bool ValidateCreateContext(const ValidationContext *val,
2463 const Display *display,
2464 const Config *configuration,
2465 gl::ContextID shareContextID,
2466 const AttributeMap &attributes)
2467{
2468 if (configuration)
2469 {
2470 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, configuration));
2471 }
2472 else
2473 {
2474 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
2475 const DisplayExtensions &displayExtensions = display->getExtensions();
2476 if (!displayExtensions.noConfigContext)
2477 {
2478 val->setError(EGL_BAD_CONFIG);
2479 return false;
2480 }
2481 }
2482
2483 if (shareContextID.value != 0)
2484 {
2485 // Shared context is invalid or is owned by another display
2486 if (!display->isValidContext(contextID: shareContextID))
2487 {
2488 val->setError(EGL_BAD_MATCH);
2489 return false;
2490 }
2491 }
2492
2493 const gl::Context *shareContext = display->getContext(contextID: shareContextID);
2494
2495 ANGLE_VALIDATION_TRY(attributes.validate(val, display, ValidateCreateContextAttribute));
2496
2497 for (const auto &attributePair : attributes)
2498 {
2499 EGLAttrib attribute = attributePair.first;
2500 EGLAttrib value = attributePair.second;
2501 ANGLE_VALIDATION_TRY(
2502 ValidateCreateContextAttributeValue(val, display, shareContext, attribute, value));
2503 }
2504
2505 // Get the requested client version (default is 1) and check it is 2 or 3.
2506 EGLAttrib clientMajorVersion = attributes.get(EGL_CONTEXT_CLIENT_VERSION, defaultValue: 1);
2507 EGLAttrib clientMinorVersion = attributes.get(EGL_CONTEXT_MINOR_VERSION, defaultValue: 0);
2508 EGLenum api = val->eglThread->getAPI();
2509
2510 switch (api)
2511 {
2512 case EGL_OPENGL_ES_API:
2513 switch (clientMajorVersion)
2514 {
2515 case 1:
2516 if (clientMinorVersion != 0 && clientMinorVersion != 1)
2517 {
2518 val->setError(EGL_BAD_ATTRIBUTE);
2519 return false;
2520 }
2521 if (configuration == EGL_NO_CONFIG_KHR)
2522 {
2523 val->setError(EGL_BAD_MATCH);
2524 return false;
2525 }
2526 if ((configuration != EGL_NO_CONFIG_KHR) &&
2527 !(configuration->renderableType & EGL_OPENGL_ES_BIT))
2528 {
2529 val->setError(EGL_BAD_MATCH);
2530 return false;
2531 }
2532 break;
2533
2534 case 2:
2535 if (clientMinorVersion != 0)
2536 {
2537 val->setError(EGL_BAD_ATTRIBUTE);
2538 return false;
2539 }
2540 if ((configuration != EGL_NO_CONFIG_KHR) &&
2541 !(configuration->renderableType & EGL_OPENGL_ES2_BIT))
2542 {
2543 val->setError(EGL_BAD_MATCH);
2544 return false;
2545 }
2546 break;
2547 case 3:
2548 if (clientMinorVersion < 0 || clientMinorVersion > 2)
2549 {
2550 val->setError(EGL_BAD_ATTRIBUTE);
2551 return false;
2552 }
2553 if ((configuration != EGL_NO_CONFIG_KHR) &&
2554 !(configuration->renderableType & EGL_OPENGL_ES3_BIT))
2555 {
2556 val->setError(EGL_BAD_MATCH);
2557 return false;
2558 }
2559 if (display->getMaxSupportedESVersion() <
2560 gl::Version(static_cast<GLuint>(clientMajorVersion),
2561 static_cast<GLuint>(clientMinorVersion)))
2562 {
2563 gl::Version max = display->getMaxSupportedESVersion();
2564 val->setError(EGL_BAD_ATTRIBUTE,
2565 message: "Requested GLES version (%" PRIxPTR ".%" PRIxPTR
2566 ") is greater than "
2567 "max supported (%d, %d).",
2568 clientMajorVersion, clientMinorVersion, max.major, max.minor);
2569 return false;
2570 }
2571 if ((attributes.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) ==
2572 EGL_TRUE) &&
2573 (clientMinorVersion > 1))
2574 {
2575 val->setError(EGL_BAD_ATTRIBUTE,
2576 message: "Requested GLES version (%" PRIxPTR ".%" PRIxPTR
2577 ") is greater than "
2578 "max supported 3.1 for WebGL.",
2579 clientMajorVersion, clientMinorVersion);
2580 return false;
2581 }
2582 break;
2583 default:
2584 val->setError(EGL_BAD_ATTRIBUTE);
2585 return false;
2586 }
2587 break;
2588
2589 case EGL_OPENGL_API:
2590 // The requested configuration must use EGL_OPENGL_BIT if EGL_OPENGL_BIT is the
2591 // currently bound API.
2592 if ((configuration != EGL_NO_CONFIG_KHR) &&
2593 !(configuration->renderableType & EGL_OPENGL_BIT))
2594 {
2595 val->setError(EGL_BAD_CONFIG);
2596 return false;
2597 }
2598 // TODO(http://anglebug.com/7533): validate desktop OpenGL versions and profile mask
2599 break;
2600
2601 default:
2602 val->setError(EGL_BAD_MATCH, message: "Unsupported API.");
2603 return false;
2604 }
2605
2606 return true;
2607}
2608
2609bool ValidateCreateWindowSurface(const ValidationContext *val,
2610 const Display *display,
2611 const Config *config,
2612 EGLNativeWindowType window,
2613 const AttributeMap &attributes)
2614{
2615 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, config));
2616
2617 if (!display->isValidNativeWindow(window))
2618 {
2619 val->setError(EGL_BAD_NATIVE_WINDOW);
2620 return false;
2621 }
2622
2623 const DisplayExtensions &displayExtensions = display->getExtensions();
2624
2625 attributes.initializeWithoutValidation();
2626
2627 for (const auto &attributeIter : attributes)
2628 {
2629 EGLAttrib attribute = attributeIter.first;
2630 EGLAttrib value = attributeIter.second;
2631
2632 switch (attribute)
2633 {
2634 case EGL_RENDER_BUFFER:
2635 switch (value)
2636 {
2637 case EGL_BACK_BUFFER:
2638 break;
2639 case EGL_SINGLE_BUFFER:
2640 break;
2641 default:
2642 val->setError(EGL_BAD_ATTRIBUTE);
2643 return false;
2644 }
2645 break;
2646
2647 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
2648 if (!displayExtensions.postSubBuffer)
2649 {
2650 val->setError(EGL_BAD_ATTRIBUTE);
2651 return false;
2652 }
2653 break;
2654
2655 case EGL_WIDTH:
2656 case EGL_HEIGHT:
2657 if (!displayExtensions.windowFixedSize)
2658 {
2659 val->setError(EGL_BAD_ATTRIBUTE);
2660 return false;
2661 }
2662 if (value < 0)
2663 {
2664 val->setError(EGL_BAD_PARAMETER);
2665 return false;
2666 }
2667 break;
2668
2669 case EGL_FIXED_SIZE_ANGLE:
2670 if (!displayExtensions.windowFixedSize)
2671 {
2672 val->setError(EGL_BAD_ATTRIBUTE);
2673 return false;
2674 }
2675 break;
2676
2677 case EGL_SURFACE_ORIENTATION_ANGLE:
2678 if (!displayExtensions.surfaceOrientation)
2679 {
2680 val->setError(EGL_BAD_ATTRIBUTE,
2681 message: "EGL_ANGLE_surface_orientation is not enabled.");
2682 return false;
2683 }
2684 break;
2685
2686 case EGL_VG_COLORSPACE:
2687 if (value != EGL_VG_COLORSPACE_sRGB)
2688 {
2689 val->setError(EGL_BAD_MATCH);
2690 return false;
2691 }
2692 break;
2693
2694 case EGL_GL_COLORSPACE:
2695 ANGLE_VALIDATION_TRY(ValidateColorspaceAttribute(val, displayExtensions, value));
2696 break;
2697
2698 case EGL_VG_ALPHA_FORMAT:
2699 val->setError(EGL_BAD_MATCH);
2700 return false;
2701
2702 case EGL_DIRECT_COMPOSITION_ANGLE:
2703 if (!displayExtensions.directComposition)
2704 {
2705 val->setError(EGL_BAD_ATTRIBUTE);
2706 return false;
2707 }
2708 break;
2709
2710 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
2711 if (!display->getExtensions().robustResourceInitializationANGLE)
2712 {
2713 val->setError(EGL_BAD_ATTRIBUTE,
2714 message: "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE "
2715 "requires EGL_ANGLE_robust_resource_initialization.");
2716 return false;
2717 }
2718 if (value != EGL_TRUE && value != EGL_FALSE)
2719 {
2720 val->setError(EGL_BAD_ATTRIBUTE,
2721 message: "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be "
2722 "either EGL_TRUE or EGL_FALSE.");
2723 return false;
2724 }
2725 break;
2726
2727 case EGL_GGP_STREAM_DESCRIPTOR_ANGLE:
2728 if (!display->getExtensions().ggpStreamDescriptor)
2729 {
2730 val->setError(EGL_BAD_ATTRIBUTE,
2731 message: "EGL_GGP_STREAM_DESCRIPTOR_ANGLE requires "
2732 "EGL_ANGLE_ggp_stream_descriptor.");
2733 return false;
2734 }
2735 break;
2736
2737 case EGL_PROTECTED_CONTENT_EXT:
2738 if (!displayExtensions.protectedContentEXT)
2739 {
2740 val->setError(EGL_BAD_ATTRIBUTE,
2741 message: "Attribute EGL_PROTECTED_CONTEXT_EXT requires "
2742 "extension EGL_EXT_protected_content.");
2743 return false;
2744 }
2745 if (value != EGL_TRUE && value != EGL_FALSE)
2746 {
2747 val->setError(EGL_BAD_ATTRIBUTE,
2748 message: "EGL_PROTECTED_CONTENT_EXT must "
2749 "be either EGL_TRUE or EGL_FALSE.");
2750 return false;
2751 }
2752 break;
2753
2754 case EGL_SWAP_INTERVAL_ANGLE:
2755 if (!displayExtensions.createSurfaceSwapIntervalANGLE)
2756 {
2757 val->setError(EGL_BAD_ATTRIBUTE,
2758 message: "Attribute EGL_SWAP_INTERVAL_ANGLE requires "
2759 "extension EGL_ANGLE_create_surface_swap_interval.");
2760 return false;
2761 }
2762 if (value < config->minSwapInterval || value > config->maxSwapInterval)
2763 {
2764 val->setError(EGL_BAD_ATTRIBUTE,
2765 message: "EGL_SWAP_INTERVAL_ANGLE must "
2766 "be within the EGLConfig min and max swap intervals.");
2767 return false;
2768 }
2769 break;
2770
2771 default:
2772 val->setError(EGL_BAD_ATTRIBUTE);
2773 return false;
2774 }
2775 }
2776
2777 if (Display::hasExistingWindowSurface(window))
2778 {
2779 val->setError(EGL_BAD_ALLOC);
2780 return false;
2781 }
2782
2783 return true;
2784}
2785
2786bool ValidateCreatePbufferSurface(const ValidationContext *val,
2787 const Display *display,
2788 const Config *config,
2789 const AttributeMap &attributes)
2790{
2791 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, config));
2792 ANGLE_VALIDATION_TRY(attributes.validate(val, display, ValidateCreatePbufferSurfaceAttribute));
2793
2794 for (const auto &attributeIter : attributes)
2795 {
2796 EGLAttrib attribute = attributeIter.first;
2797 EGLAttrib value = attributeIter.second;
2798
2799 ANGLE_VALIDATION_TRY(
2800 ValidateCreatePbufferSurfaceAttributeValue(val, display, attribute, value));
2801 }
2802
2803 if ((config->surfaceType & EGL_PBUFFER_BIT) == 0)
2804 {
2805 val->setError(EGL_BAD_MATCH);
2806 return false;
2807 }
2808
2809 const Caps &caps = display->getCaps();
2810
2811 EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
2812 EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
2813
2814 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
2815 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
2816 {
2817 val->setError(EGL_BAD_MATCH);
2818 return false;
2819 }
2820
2821 if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) ||
2822 (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
2823 {
2824 val->setError(EGL_BAD_ATTRIBUTE);
2825 return false;
2826 }
2827
2828 EGLint width = static_cast<EGLint>(attributes.get(EGL_WIDTH, defaultValue: 0));
2829 EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, defaultValue: 0));
2830 if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT &&
2831 (!gl::isPow2(x: width) || !gl::isPow2(x: height)))
2832 {
2833 val->setError(EGL_BAD_MATCH);
2834 return false;
2835 }
2836
2837 return true;
2838}
2839
2840bool ValidateCreatePbufferFromClientBuffer(const ValidationContext *val,
2841 const Display *display,
2842 EGLenum buftype,
2843 EGLClientBuffer buffer,
2844 const Config *config,
2845 const AttributeMap &attributes)
2846{
2847 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, config));
2848
2849 const DisplayExtensions &displayExtensions = display->getExtensions();
2850
2851 attributes.initializeWithoutValidation();
2852
2853 switch (buftype)
2854 {
2855 case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
2856 if (!displayExtensions.d3dShareHandleClientBuffer)
2857 {
2858 val->setError(EGL_BAD_PARAMETER);
2859 return false;
2860 }
2861 if (buffer == nullptr)
2862 {
2863 val->setError(EGL_BAD_PARAMETER);
2864 return false;
2865 }
2866 break;
2867
2868 case EGL_D3D_TEXTURE_ANGLE:
2869 if (!displayExtensions.d3dTextureClientBuffer)
2870 {
2871 val->setError(EGL_BAD_PARAMETER);
2872 return false;
2873 }
2874 if (buffer == nullptr)
2875 {
2876 val->setError(EGL_BAD_PARAMETER);
2877 return false;
2878 }
2879 break;
2880
2881 case EGL_IOSURFACE_ANGLE:
2882 if (!displayExtensions.iosurfaceClientBuffer)
2883 {
2884 val->setError(EGL_BAD_PARAMETER,
2885 message: "<buftype> EGL_IOSURFACE_ANGLE requires the "
2886 "EGL_ANGLE_iosurface_client_buffer extension.");
2887 return false;
2888 }
2889 if (buffer == nullptr)
2890 {
2891 val->setError(EGL_BAD_PARAMETER, message: "<buffer> must be non null");
2892 return false;
2893 }
2894 break;
2895 case EGL_EXTERNAL_SURFACE_ANGLE:
2896 if (!display->getExtensions().externalContextAndSurface)
2897 {
2898 val->setError(EGL_BAD_ATTRIBUTE,
2899 message: "Attribute "
2900 "EGL_EXTERNAL_SURFACE_ANGLE requires "
2901 "EGL_ANGLE_external_context_and_surface.");
2902 return false;
2903 }
2904 if (buffer != nullptr)
2905 {
2906 val->setError(EGL_BAD_PARAMETER, message: "<buffer> must be null");
2907 return false;
2908 }
2909 break;
2910
2911 default:
2912 val->setError(EGL_BAD_PARAMETER);
2913 return false;
2914 }
2915
2916 for (AttributeMap::const_iterator attributeIter = attributes.begin();
2917 attributeIter != attributes.end(); attributeIter++)
2918 {
2919 EGLAttrib attribute = attributeIter->first;
2920 EGLAttrib value = attributeIter->second;
2921
2922 switch (attribute)
2923 {
2924 case EGL_WIDTH:
2925 case EGL_HEIGHT:
2926 if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE &&
2927 buftype != EGL_D3D_TEXTURE_ANGLE && buftype != EGL_IOSURFACE_ANGLE &&
2928 buftype != EGL_EXTERNAL_SURFACE_ANGLE)
2929 {
2930 val->setError(EGL_BAD_PARAMETER,
2931 message: "Width and Height are not supported for this <buftype>");
2932 return false;
2933 }
2934 if (value < 0)
2935 {
2936 val->setError(EGL_BAD_PARAMETER, message: "Width and Height must be positive");
2937 return false;
2938 }
2939 break;
2940
2941 case EGL_TEXTURE_FORMAT:
2942 switch (value)
2943 {
2944 case EGL_NO_TEXTURE:
2945 case EGL_TEXTURE_RGB:
2946 case EGL_TEXTURE_RGBA:
2947 break;
2948 default:
2949 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid value for EGL_TEXTURE_FORMAT");
2950 return false;
2951 }
2952 break;
2953
2954 case EGL_TEXTURE_TARGET:
2955 switch (value)
2956 {
2957 case EGL_NO_TEXTURE:
2958 case EGL_TEXTURE_2D:
2959 break;
2960 case EGL_TEXTURE_RECTANGLE_ANGLE:
2961 if (buftype != EGL_IOSURFACE_ANGLE)
2962 {
2963 val->setError(EGL_BAD_PARAMETER,
2964 message: "<buftype> doesn't support rectangle texture targets");
2965 return false;
2966 }
2967 break;
2968
2969 default:
2970 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid value for EGL_TEXTURE_TARGET");
2971 return false;
2972 }
2973 break;
2974
2975 case EGL_MIPMAP_TEXTURE:
2976 break;
2977
2978 case EGL_IOSURFACE_PLANE_ANGLE:
2979 if (buftype != EGL_IOSURFACE_ANGLE)
2980 {
2981 val->setError(EGL_BAD_ATTRIBUTE, message: "<buftype> doesn't support iosurface plane");
2982 return false;
2983 }
2984 break;
2985
2986 case EGL_TEXTURE_TYPE_ANGLE:
2987 if (buftype != EGL_IOSURFACE_ANGLE)
2988 {
2989 val->setError(EGL_BAD_ATTRIBUTE, message: "<buftype> doesn't support texture type");
2990 return false;
2991 }
2992 break;
2993
2994 case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
2995 if (buftype != EGL_IOSURFACE_ANGLE && buftype != EGL_D3D_TEXTURE_ANGLE)
2996 {
2997 val->setError(EGL_BAD_ATTRIBUTE,
2998 message: "<buftype> doesn't support texture internal format");
2999 return false;
3000 }
3001 break;
3002
3003 case EGL_GL_COLORSPACE:
3004 if (buftype != EGL_D3D_TEXTURE_ANGLE)
3005 {
3006 val->setError(EGL_BAD_ATTRIBUTE,
3007 message: "<buftype> doesn't support setting GL colorspace");
3008 return false;
3009 }
3010 break;
3011
3012 case EGL_IOSURFACE_USAGE_HINT_ANGLE:
3013 if (value & ~(EGL_IOSURFACE_READ_HINT_ANGLE | EGL_IOSURFACE_WRITE_HINT_ANGLE))
3014 {
3015 val->setError(EGL_BAD_ATTRIBUTE,
3016 message: "IOSurface usage hint must only contain READ or WRITE");
3017 return false;
3018 }
3019 break;
3020
3021 case EGL_TEXTURE_OFFSET_X_ANGLE:
3022 case EGL_TEXTURE_OFFSET_Y_ANGLE:
3023 if (buftype != EGL_D3D_TEXTURE_ANGLE)
3024 {
3025 val->setError(EGL_BAD_ATTRIBUTE,
3026 message: "<buftype> doesn't support setting texture offset");
3027 return false;
3028 }
3029 break;
3030
3031 case EGL_PROTECTED_CONTENT_EXT:
3032 if (!displayExtensions.protectedContentEXT)
3033 {
3034 val->setError(EGL_BAD_ATTRIBUTE,
3035 message: "Attribute EGL_PROTECTED_CONTEXT_EXT requires "
3036 "extension EGL_EXT_protected_content.");
3037 return false;
3038 }
3039 if (value != EGL_TRUE && value != EGL_FALSE)
3040 {
3041 val->setError(EGL_BAD_ATTRIBUTE,
3042 message: "EGL_PROTECTED_CONTENT_EXT must "
3043 "be either EGL_TRUE or EGL_FALSE.");
3044 return false;
3045 }
3046 break;
3047
3048 default:
3049 val->setError(EGL_BAD_ATTRIBUTE);
3050 return false;
3051 }
3052 }
3053
3054 EGLAttrib colorspace = attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR);
3055 if (colorspace != EGL_GL_COLORSPACE_LINEAR && colorspace != EGL_GL_COLORSPACE_SRGB)
3056 {
3057 val->setError(EGL_BAD_ATTRIBUTE, message: "invalid GL colorspace");
3058 return false;
3059 }
3060
3061 if (!(config->surfaceType & EGL_PBUFFER_BIT))
3062 {
3063 val->setError(EGL_BAD_MATCH);
3064 return false;
3065 }
3066
3067 EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE);
3068 EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE);
3069 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
3070 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
3071 {
3072 val->setError(EGL_BAD_MATCH);
3073 return false;
3074 }
3075 if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) ||
3076 (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
3077 {
3078 // TODO(cwallez@chromium.org): For IOSurface pbuffers we require that EGL_TEXTURE_RGBA is
3079 // set so that eglBindTexImage works. Normally this is only allowed if the config exposes
3080 // the bindToTextureRGB/RGBA flag. This issue is that enabling this flags means that
3081 // eglBindTexImage should also work for regular pbuffers which isn't implemented on macOS.
3082 // Instead of adding the flag we special case the check here to be ignored for IOSurfaces.
3083 // The TODO is to find a proper solution for this, maybe by implementing eglBindTexImage on
3084 // OSX?
3085 if (buftype != EGL_IOSURFACE_ANGLE)
3086 {
3087 val->setError(EGL_BAD_ATTRIBUTE);
3088 return false;
3089 }
3090 }
3091
3092 if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
3093 {
3094 EGLint width = static_cast<EGLint>(attributes.get(EGL_WIDTH, defaultValue: 0));
3095 EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, defaultValue: 0));
3096
3097 if (width == 0 || height == 0)
3098 {
3099 val->setError(EGL_BAD_ATTRIBUTE);
3100 return false;
3101 }
3102
3103 const Caps &caps = display->getCaps();
3104 if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT &&
3105 (!gl::isPow2(x: width) || !gl::isPow2(x: height)))
3106 {
3107 val->setError(EGL_BAD_MATCH);
3108 return false;
3109 }
3110 }
3111
3112 if (buftype == EGL_IOSURFACE_ANGLE)
3113 {
3114 if (static_cast<EGLenum>(textureTarget) != config->bindToTextureTarget)
3115 {
3116 val->setError(EGL_BAD_ATTRIBUTE,
3117 message: "EGL_IOSURFACE requires the texture target to match the config");
3118 return false;
3119 }
3120 if (textureFormat != EGL_TEXTURE_RGBA)
3121 {
3122 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_IOSURFACE requires the EGL_TEXTURE_RGBA format");
3123 return false;
3124 }
3125
3126 if (!attributes.contains(EGL_WIDTH) || !attributes.contains(EGL_HEIGHT) ||
3127 !attributes.contains(EGL_TEXTURE_FORMAT) ||
3128 !attributes.contains(EGL_TEXTURE_TYPE_ANGLE) ||
3129 !attributes.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE) ||
3130 !attributes.contains(EGL_IOSURFACE_PLANE_ANGLE))
3131 {
3132 val->setError(EGL_BAD_PARAMETER, message: "Missing required attribute for EGL_IOSURFACE");
3133 return false;
3134 }
3135 }
3136
3137 ANGLE_EGL_TRY_RETURN(val->eglThread,
3138 display->validateClientBuffer(config, buftype, buffer, attributes),
3139 val->entryPoint, val->labeledObject, false);
3140
3141 return true;
3142}
3143
3144bool ValidateCreatePixmapSurface(const ValidationContext *val,
3145 const Display *display,
3146 const Config *config,
3147 EGLNativePixmapType pixmap,
3148 const AttributeMap &attributes)
3149{
3150 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, config));
3151
3152 const DisplayExtensions &displayExtensions = display->getExtensions();
3153
3154 attributes.initializeWithoutValidation();
3155
3156 for (const auto &attributePair : attributes)
3157 {
3158 EGLAttrib attribute = attributePair.first;
3159 EGLAttrib value = attributePair.second;
3160
3161 switch (attribute)
3162 {
3163 case EGL_GL_COLORSPACE:
3164 ANGLE_VALIDATION_TRY(ValidateColorspaceAttribute(val, displayExtensions, value));
3165 break;
3166
3167 case EGL_VG_COLORSPACE:
3168 break;
3169 case EGL_VG_ALPHA_FORMAT:
3170 break;
3171
3172 case EGL_TEXTURE_FORMAT:
3173 if (!displayExtensions.textureFromPixmapNOK)
3174 {
3175 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_NOK_texture_from_pixmap is not enabled.");
3176 return false;
3177 }
3178 switch (value)
3179 {
3180 case EGL_NO_TEXTURE:
3181 case EGL_TEXTURE_RGB:
3182 case EGL_TEXTURE_RGBA:
3183 break;
3184 default:
3185 val->setError(EGL_BAD_ATTRIBUTE);
3186 return false;
3187 }
3188 break;
3189
3190 case EGL_TEXTURE_TARGET:
3191 if (!displayExtensions.textureFromPixmapNOK)
3192 {
3193 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_NOK_texture_from_pixmap is not enabled.");
3194 return false;
3195 }
3196 switch (value)
3197 {
3198 case EGL_NO_TEXTURE:
3199 case EGL_TEXTURE_2D:
3200 break;
3201 default:
3202 val->setError(EGL_BAD_ATTRIBUTE);
3203 return false;
3204 }
3205 break;
3206
3207 case EGL_MIPMAP_TEXTURE:
3208 if (!displayExtensions.textureFromPixmapNOK)
3209 {
3210 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_NOK_texture_from_pixmap is not enabled.");
3211 return false;
3212 }
3213 break;
3214
3215 case EGL_PROTECTED_CONTENT_EXT:
3216 if (!displayExtensions.protectedContentEXT)
3217 {
3218 val->setError(EGL_BAD_ATTRIBUTE,
3219 message: "Attribute EGL_PROTECTED_CONTEXT_EXT requires "
3220 "extension EGL_EXT_protected_content.");
3221 return false;
3222 }
3223 if (value != EGL_TRUE && value != EGL_FALSE)
3224 {
3225 val->setError(EGL_BAD_ATTRIBUTE,
3226 message: "EGL_PROTECTED_CONTENT_EXT must "
3227 "be either EGL_TRUE or EGL_FALSE.");
3228 return false;
3229 }
3230 break;
3231
3232 default:
3233 val->setError(EGL_BAD_ATTRIBUTE, message: "Unknown attribute: 0x%04" PRIxPTR, attribute);
3234 return false;
3235 }
3236 }
3237
3238 if (!(config->surfaceType & EGL_PIXMAP_BIT))
3239 {
3240 val->setError(EGL_BAD_MATCH, message: "Congfig does not suport pixmaps.");
3241 return false;
3242 }
3243
3244 ANGLE_EGL_TRY_RETURN(val->eglThread, display->valdiatePixmap(config, pixmap, attributes),
3245 val->entryPoint, val->labeledObject, false);
3246
3247 return true;
3248}
3249
3250bool ValidateMakeCurrent(const ValidationContext *val,
3251 const Display *display,
3252 SurfaceID drawSurfaceID,
3253 SurfaceID readSurfaceID,
3254 gl::ContextID contextID)
3255{
3256 bool noDraw = drawSurfaceID.value == 0;
3257 bool noRead = readSurfaceID.value == 0;
3258 bool noContext = contextID.value == 0;
3259
3260 if (noContext && (!noDraw || !noRead))
3261 {
3262 val->setError(EGL_BAD_MATCH, message: "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE");
3263 return false;
3264 }
3265
3266 // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH
3267 // error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE.
3268 if (!noContext && (noDraw || noRead))
3269 {
3270 if (display->getExtensions().surfacelessContext)
3271 {
3272 if (noDraw != noRead)
3273 {
3274 val->setError(EGL_BAD_MATCH,
3275 message: "If ctx is not EGL_NOT_CONTEXT, draw or read must "
3276 "both be EGL_NO_SURFACE, or both not");
3277 return false;
3278 }
3279 }
3280 else
3281 {
3282 val->setError(EGL_BAD_MATCH,
3283 message: "If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE");
3284 return false;
3285 }
3286 }
3287
3288 // If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an
3289 // EGL_BAD_MATCH error is generated.
3290 if (noRead != noDraw)
3291 {
3292 val->setError(EGL_BAD_MATCH,
3293 message: "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE");
3294 return false;
3295 }
3296
3297 if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
3298 {
3299 val->setError(EGL_BAD_DISPLAY, message: "'dpy' not a valid EGLDisplay handle");
3300 return false;
3301 }
3302
3303 // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null
3304 if (!display->isInitialized() && (!noContext || !noDraw || !noRead))
3305 {
3306 val->setError(EGL_NOT_INITIALIZED, message: "'dpy' not initialized");
3307 return false;
3308 }
3309
3310 if (!noContext)
3311 {
3312 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
3313 }
3314
3315 if (display->isInitialized() && display->isDeviceLost())
3316 {
3317 val->setError(EGL_CONTEXT_LOST);
3318 return false;
3319 }
3320
3321 if (!noDraw)
3322 {
3323 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, drawSurfaceID));
3324 }
3325
3326 const Surface *drawSurface = GetSurfaceIfValid(display, surfaceID: drawSurfaceID);
3327 const Surface *readSurface = GetSurfaceIfValid(display, surfaceID: readSurfaceID);
3328 const gl::Context *context = GetContextIfValid(display, contextID);
3329
3330 if (!noRead)
3331 {
3332 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, readSurfaceID));
3333 ANGLE_VALIDATION_TRY(ValidateCompatibleSurface(val, display, context, readSurface));
3334 }
3335
3336 if (drawSurface != readSurface)
3337 {
3338 if (drawSurface)
3339 {
3340 ANGLE_VALIDATION_TRY(ValidateCompatibleSurface(val, display, context, drawSurface));
3341 }
3342 if (readSurface)
3343 {
3344 ANGLE_VALIDATION_TRY(ValidateCompatibleSurface(val, display, context, readSurface));
3345 }
3346 }
3347 return true;
3348}
3349
3350bool ValidateCreateImage(const ValidationContext *val,
3351 const Display *display,
3352 gl::ContextID contextID,
3353 EGLenum target,
3354 EGLClientBuffer buffer,
3355 const AttributeMap &attributes)
3356{
3357 const gl::Context *context = GetContextIfValid(display, contextID);
3358
3359 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
3360
3361 attributes.initializeWithoutValidation();
3362
3363 const DisplayExtensions &displayExtensions = display->getExtensions();
3364
3365 // TODO(geofflang): Complete validation from EGL_KHR_image_base:
3366 // If the resource specified by <dpy>, <ctx>, <target>, <buffer> and <attrib_list> is itself an
3367 // EGLImage sibling, the error EGL_BAD_ACCESS is generated.
3368
3369 for (AttributeMap::const_iterator attributeIter = attributes.begin();
3370 attributeIter != attributes.end(); attributeIter++)
3371 {
3372 EGLAttrib attribute = attributeIter->first;
3373 EGLAttrib value = attributeIter->second;
3374
3375 switch (attribute)
3376 {
3377 case EGL_IMAGE_PRESERVED:
3378 switch (value)
3379 {
3380 case EGL_TRUE:
3381 case EGL_FALSE:
3382 break;
3383
3384 default:
3385 val->setError(EGL_BAD_PARAMETER,
3386 message: "EGL_IMAGE_PRESERVED must be EGL_TRUE or EGL_FALSE.");
3387 return false;
3388 }
3389 break;
3390
3391 case EGL_GL_TEXTURE_LEVEL:
3392 if (!displayExtensions.glTexture2DImage &&
3393 !displayExtensions.glTextureCubemapImage && !displayExtensions.glTexture3DImage)
3394 {
3395 val->setError(EGL_BAD_PARAMETER,
3396 message: "EGL_GL_TEXTURE_LEVEL cannot be used "
3397 "without KHR_gl_texture_*_image support.");
3398 return false;
3399 }
3400
3401 if (value < 0)
3402 {
3403 val->setError(EGL_BAD_PARAMETER, message: "EGL_GL_TEXTURE_LEVEL cannot be negative.");
3404 return false;
3405 }
3406 break;
3407
3408 case EGL_GL_TEXTURE_ZOFFSET:
3409 if (!displayExtensions.glTexture3DImage)
3410 {
3411 val->setError(EGL_BAD_PARAMETER,
3412 message: "EGL_GL_TEXTURE_ZOFFSET cannot be used "
3413 "without KHR_gl_texture_3D_image support.");
3414 return false;
3415 }
3416 break;
3417
3418 case EGL_GL_COLORSPACE:
3419 if (!displayExtensions.glColorspace)
3420 {
3421 val->setError(EGL_BAD_PARAMETER,
3422 message: "EGL_GL_COLORSPACE cannot be used "
3423 "without EGL_KHR_gl_colorspace support.");
3424 return false;
3425 }
3426 switch (value)
3427 {
3428 case EGL_GL_COLORSPACE_DEFAULT_EXT:
3429 break;
3430 default:
3431 ANGLE_VALIDATION_TRY(
3432 ValidateColorspaceAttribute(val, displayExtensions, value));
3433 break;
3434 }
3435 break;
3436
3437 case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
3438 if (!displayExtensions.imageD3D11Texture && !displayExtensions.vulkanImageANGLE)
3439 {
3440 val->setError(
3441 EGL_BAD_PARAMETER,
3442 message: "EGL_TEXTURE_INTERNAL_FORMAT_ANGLE cannot be used without "
3443 "EGL_ANGLE_image_d3d11_texture or EGL_ANGLE_vulkan_image support.");
3444 return false;
3445 }
3446 break;
3447
3448 case EGL_D3D11_TEXTURE_PLANE_ANGLE:
3449 if (!displayExtensions.imageD3D11Texture)
3450 {
3451 val->setError(EGL_BAD_ATTRIBUTE,
3452 message: "EGL_D3D11_TEXTURE_PLANE_ANGLE cannot be used without "
3453 "EGL_ANGLE_image_d3d11_texture support.");
3454 return false;
3455 }
3456 break;
3457
3458 case EGL_D3D11_TEXTURE_ARRAY_SLICE_ANGLE:
3459 if (!displayExtensions.imageD3D11Texture)
3460 {
3461 val->setError(EGL_BAD_ATTRIBUTE,
3462 message: "EGL_D3D11_TEXTURE_ARRAY_SLICE_ANGLE cannot be used without "
3463 "EGL_ANGLE_image_d3d11_texture support.");
3464 return false;
3465 }
3466 break;
3467
3468 case EGL_WIDTH:
3469 case EGL_HEIGHT:
3470 if (target != EGL_LINUX_DMA_BUF_EXT)
3471 {
3472 val->setError(
3473 EGL_BAD_PARAMETER,
3474 message: "Parameter cannot be used if target is not EGL_LINUX_DMA_BUF_EXT");
3475 return false;
3476 }
3477 break;
3478
3479 case EGL_LINUX_DRM_FOURCC_EXT:
3480 case EGL_DMA_BUF_PLANE0_FD_EXT:
3481 case EGL_DMA_BUF_PLANE0_OFFSET_EXT:
3482 case EGL_DMA_BUF_PLANE0_PITCH_EXT:
3483 case EGL_DMA_BUF_PLANE1_FD_EXT:
3484 case EGL_DMA_BUF_PLANE1_OFFSET_EXT:
3485 case EGL_DMA_BUF_PLANE1_PITCH_EXT:
3486 case EGL_DMA_BUF_PLANE2_FD_EXT:
3487 case EGL_DMA_BUF_PLANE2_OFFSET_EXT:
3488 case EGL_DMA_BUF_PLANE2_PITCH_EXT:
3489 if (!displayExtensions.imageDmaBufImportEXT)
3490 {
3491 val->setError(EGL_BAD_PARAMETER,
3492 message: "Parameter cannot be used without "
3493 "EGL_EXT_image_dma_buf_import support.");
3494 return false;
3495 }
3496 break;
3497
3498 case EGL_YUV_COLOR_SPACE_HINT_EXT:
3499 if (!displayExtensions.imageDmaBufImportEXT)
3500 {
3501 val->setError(EGL_BAD_PARAMETER,
3502 message: "Parameter cannot be used without "
3503 "EGL_EXT_image_dma_buf_import support.");
3504 return false;
3505 }
3506
3507 switch (value)
3508 {
3509 case EGL_ITU_REC601_EXT:
3510 case EGL_ITU_REC709_EXT:
3511 case EGL_ITU_REC2020_EXT:
3512 break;
3513
3514 default:
3515 val->setError(EGL_BAD_PARAMETER,
3516 message: "Invalid value for EGL_YUV_COLOR_SPACE_HINT_EXT.");
3517 return false;
3518 }
3519 break;
3520
3521 case EGL_SAMPLE_RANGE_HINT_EXT:
3522 if (!displayExtensions.imageDmaBufImportEXT)
3523 {
3524 val->setError(EGL_BAD_PARAMETER,
3525 message: "Parameter cannot be used without "
3526 "EGL_EXT_image_dma_buf_import support.");
3527 return false;
3528 }
3529
3530 switch (value)
3531 {
3532 case EGL_YUV_FULL_RANGE_EXT:
3533 case EGL_YUV_NARROW_RANGE_EXT:
3534 break;
3535
3536 default:
3537 val->setError(EGL_BAD_PARAMETER,
3538 message: "Invalid value for EGL_SAMPLE_RANGE_HINT_EXT.");
3539 return false;
3540 }
3541 break;
3542
3543 case EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT:
3544 case EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT:
3545 if (!displayExtensions.imageDmaBufImportEXT)
3546 {
3547 val->setError(EGL_BAD_PARAMETER,
3548 message: "Parameter cannot be used without "
3549 "EGL_EXT_image_dma_buf_import support.");
3550 return false;
3551 }
3552
3553 switch (value)
3554 {
3555 case EGL_YUV_CHROMA_SITING_0_EXT:
3556 case EGL_YUV_CHROMA_SITING_0_5_EXT:
3557 break;
3558
3559 default:
3560 val->setError(
3561 EGL_BAD_PARAMETER,
3562 message: "Invalid value for EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT or "
3563 "EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT.");
3564 return false;
3565 }
3566 break;
3567
3568 case EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT:
3569 case EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT:
3570 case EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT:
3571 case EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT:
3572 case EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT:
3573 case EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT:
3574 case EGL_DMA_BUF_PLANE3_FD_EXT:
3575 case EGL_DMA_BUF_PLANE3_OFFSET_EXT:
3576 case EGL_DMA_BUF_PLANE3_PITCH_EXT:
3577 case EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT:
3578 case EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT:
3579 if (!displayExtensions.imageDmaBufImportModifiersEXT)
3580 {
3581 val->setError(EGL_BAD_PARAMETER,
3582 message: "Parameter cannot be used without "
3583 "EGL_EXT_image_dma_buf_import_modifiers support.");
3584 return false;
3585 }
3586 break;
3587
3588 case EGL_PROTECTED_CONTENT_EXT:
3589 if (!displayExtensions.protectedContentEXT)
3590 {
3591 val->setError(EGL_BAD_ATTRIBUTE,
3592 message: "Attribute EGL_PROTECTED_CONTEXT_EXT requires "
3593 "extension EGL_EXT_protected_content.");
3594 return false;
3595 }
3596 if (value != EGL_TRUE && value != EGL_FALSE)
3597 {
3598 val->setError(EGL_BAD_ATTRIBUTE,
3599 message: "EGL_PROTECTED_CONTENT_EXT must "
3600 "be either EGL_TRUE or EGL_FALSE.");
3601 return false;
3602 }
3603 break;
3604
3605 case EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE:
3606 case EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE:
3607 if (!displayExtensions.vulkanImageANGLE)
3608 {
3609 val->setError(EGL_BAD_ATTRIBUTE,
3610 message: "Attribute EGL_VULKAN_IMAGE_CREATE_INFO_{HI,LO}_ANGLE require "
3611 "extension EGL_ANGLE_vulkan_image.");
3612 return false;
3613 }
3614 break;
3615
3616 default:
3617 val->setError(EGL_BAD_PARAMETER, message: "invalid attribute: 0x%04" PRIxPTR "X", attribute);
3618 return false;
3619 }
3620 }
3621
3622 switch (target)
3623 {
3624 case EGL_GL_TEXTURE_2D:
3625 {
3626 if (!displayExtensions.glTexture2DImage)
3627 {
3628 val->setError(EGL_BAD_PARAMETER, message: "KHR_gl_texture_2D_image not supported.");
3629 return false;
3630 }
3631
3632 if (buffer == 0)
3633 {
3634 val->setError(EGL_BAD_PARAMETER,
3635 message: "buffer cannot reference a 2D texture with the name 0.");
3636 return false;
3637 }
3638
3639 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
3640 const gl::Texture *texture =
3641 context->getTexture(handle: {.value: egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
3642 if (texture == nullptr || texture->getType() != gl::TextureType::_2D)
3643 {
3644 val->setError(EGL_BAD_PARAMETER, message: "target is not a 2D texture.");
3645 return false;
3646 }
3647
3648 if (texture->getBoundSurface() != nullptr)
3649 {
3650 val->setError(EGL_BAD_ACCESS, message: "texture has a surface bound to it.");
3651 return false;
3652 }
3653
3654 EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL, defaultValue: 0);
3655 if (texture->getWidth(target: gl::TextureTarget::_2D, level: static_cast<size_t>(level)) == 0 ||
3656 texture->getHeight(target: gl::TextureTarget::_2D, level: static_cast<size_t>(level)) == 0)
3657 {
3658 val->setError(EGL_BAD_PARAMETER,
3659 message: "target 2D texture does not have a valid size at specified level.");
3660 return false;
3661 }
3662
3663 bool protectedContentAttrib =
3664 (attributes.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) != EGL_FALSE);
3665 if (protectedContentAttrib != texture->hasProtectedContent())
3666 {
3667 val->setError(EGL_BAD_PARAMETER,
3668 message: "EGL_PROTECTED_CONTENT_EXT attribute does not match protected state "
3669 "of target.");
3670 return false;
3671 }
3672
3673 ANGLE_VALIDATION_TRY(ValidateCreateImageMipLevelCommon(val, context, texture, level));
3674 }
3675 break;
3676
3677 case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
3678 case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
3679 case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
3680 case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
3681 case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
3682 case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
3683 {
3684 if (!displayExtensions.glTextureCubemapImage)
3685 {
3686 val->setError(EGL_BAD_PARAMETER, message: "KHR_gl_texture_cubemap_image not supported.");
3687 return false;
3688 }
3689
3690 if (buffer == 0)
3691 {
3692 val->setError(EGL_BAD_PARAMETER,
3693 message: "buffer cannot reference a cubemap texture with the name 0.");
3694 return false;
3695 }
3696
3697 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
3698 const gl::Texture *texture =
3699 context->getTexture(handle: {.value: egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
3700 if (texture == nullptr || texture->getType() != gl::TextureType::CubeMap)
3701 {
3702 val->setError(EGL_BAD_PARAMETER, message: "target is not a cubemap texture.");
3703 return false;
3704 }
3705
3706 if (texture->getBoundSurface() != nullptr)
3707 {
3708 val->setError(EGL_BAD_ACCESS, message: "texture has a surface bound to it.");
3709 return false;
3710 }
3711
3712 EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL, defaultValue: 0);
3713 gl::TextureTarget cubeMapFace = egl_gl::EGLCubeMapTargetToCubeMapTarget(eglTarget: target);
3714 if (texture->getWidth(target: cubeMapFace, level: static_cast<size_t>(level)) == 0 ||
3715 texture->getHeight(target: cubeMapFace, level: static_cast<size_t>(level)) == 0)
3716 {
3717 val->setError(EGL_BAD_PARAMETER,
3718 message: "target cubemap texture does not have a valid "
3719 "size at specified level and face.");
3720 return false;
3721 }
3722
3723 ANGLE_VALIDATION_TRY(ValidateCreateImageMipLevelCommon(val, context, texture, level));
3724
3725 if (level == 0 && !texture->isMipmapComplete() &&
3726 CubeTextureHasUnspecifiedLevel0Face(texture))
3727 {
3728 val->setError(EGL_BAD_PARAMETER,
3729 message: "if level is zero and the texture is incomplete, "
3730 "it must have all of its faces specified at level "
3731 "zero.");
3732 return false;
3733 }
3734
3735 bool protectedContentAttrib =
3736 (attributes.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) != EGL_FALSE);
3737 if (protectedContentAttrib != texture->hasProtectedContent())
3738 {
3739 val->setError(EGL_BAD_PARAMETER,
3740 message: "EGL_PROTECTED_CONTENT_EXT attribute does not match protected state "
3741 "of target.");
3742 return false;
3743 }
3744 }
3745 break;
3746
3747 case EGL_GL_TEXTURE_3D:
3748 {
3749 if (!displayExtensions.glTexture3DImage)
3750 {
3751 val->setError(EGL_BAD_PARAMETER, message: "KHR_gl_texture_3D_image not supported.");
3752 return false;
3753 }
3754
3755 if (buffer == 0)
3756 {
3757 val->setError(EGL_BAD_PARAMETER,
3758 message: "buffer cannot reference a 3D texture with the name 0.");
3759 return false;
3760 }
3761
3762 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
3763 const gl::Texture *texture =
3764 context->getTexture(handle: {.value: egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
3765 if (texture == nullptr || texture->getType() != gl::TextureType::_3D)
3766 {
3767 val->setError(EGL_BAD_PARAMETER, message: "target is not a 3D texture.");
3768 return false;
3769 }
3770
3771 if (texture->getBoundSurface() != nullptr)
3772 {
3773 val->setError(EGL_BAD_ACCESS, message: "texture has a surface bound to it.");
3774 return false;
3775 }
3776
3777 EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL, defaultValue: 0);
3778 EGLAttrib zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET, defaultValue: 0);
3779 if (texture->getWidth(target: gl::TextureTarget::_3D, level: static_cast<size_t>(level)) == 0 ||
3780 texture->getHeight(target: gl::TextureTarget::_3D, level: static_cast<size_t>(level)) == 0 ||
3781 texture->getDepth(target: gl::TextureTarget::_3D, level: static_cast<size_t>(level)) == 0)
3782 {
3783 val->setError(EGL_BAD_PARAMETER,
3784 message: "target 3D texture does not have a valid size at specified level.");
3785 return false;
3786 }
3787
3788 if (static_cast<size_t>(zOffset) >=
3789 texture->getDepth(target: gl::TextureTarget::_3D, level: static_cast<size_t>(level)))
3790 {
3791 val->setError(EGL_BAD_PARAMETER,
3792 message: "target 3D texture does not have enough layers "
3793 "for the specified Z offset at the specified "
3794 "level.");
3795 return false;
3796 }
3797
3798 bool protectedContentAttrib =
3799 (attributes.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) != EGL_FALSE);
3800 if (protectedContentAttrib != texture->hasProtectedContent())
3801 {
3802 val->setError(EGL_BAD_PARAMETER,
3803 message: "EGL_PROTECTED_CONTENT_EXT attribute does not match protected state "
3804 "of target.");
3805 return false;
3806 }
3807
3808 ANGLE_VALIDATION_TRY(ValidateCreateImageMipLevelCommon(val, context, texture, level));
3809 }
3810 break;
3811
3812 case EGL_GL_RENDERBUFFER:
3813 {
3814 if (!displayExtensions.glRenderbufferImage)
3815 {
3816 val->setError(EGL_BAD_PARAMETER, message: "KHR_gl_renderbuffer_image not supported.");
3817 return false;
3818 }
3819
3820 if (attributes.contains(EGL_GL_TEXTURE_LEVEL))
3821 {
3822 val->setError(EGL_BAD_PARAMETER,
3823 message: "EGL_GL_TEXTURE_LEVEL cannot be used in "
3824 "conjunction with a renderbuffer target.");
3825 return false;
3826 }
3827
3828 if (buffer == 0)
3829 {
3830 val->setError(EGL_BAD_PARAMETER,
3831 message: "buffer cannot reference a renderbuffer with the name 0.");
3832 return false;
3833 }
3834
3835 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
3836 const gl::Renderbuffer *renderbuffer =
3837 context->getRenderbuffer(handle: {.value: egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
3838 if (renderbuffer == nullptr)
3839 {
3840 val->setError(EGL_BAD_PARAMETER, message: "target is not a renderbuffer.");
3841 return false;
3842 }
3843
3844 if (renderbuffer->getSamples() > 0)
3845 {
3846 val->setError(EGL_BAD_PARAMETER, message: "target renderbuffer cannot be multisampled.");
3847 return false;
3848 }
3849
3850 bool protectedContentAttrib =
3851 (attributes.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) != EGL_FALSE);
3852 if (protectedContentAttrib != renderbuffer->hasProtectedContent())
3853 {
3854 val->setError(EGL_BAD_ACCESS,
3855 message: "EGL_PROTECTED_CONTENT_EXT attribute does not match protected state "
3856 "of target.");
3857 return false;
3858 }
3859 }
3860 break;
3861
3862 case EGL_NATIVE_BUFFER_ANDROID:
3863 {
3864 if (!displayExtensions.imageNativeBuffer)
3865 {
3866 val->setError(EGL_BAD_PARAMETER, message: "EGL_ANDROID_image_native_buffer not supported.");
3867 return false;
3868 }
3869
3870 if (context != nullptr)
3871 {
3872 val->setError(EGL_BAD_CONTEXT, message: "ctx must be EGL_NO_CONTEXT.");
3873 return false;
3874 }
3875
3876 ANGLE_EGL_TRY_RETURN(
3877 val->eglThread,
3878 display->validateImageClientBuffer(context, target, buffer, attributes),
3879 val->entryPoint, val->labeledObject, false);
3880 }
3881 break;
3882
3883 case EGL_D3D11_TEXTURE_ANGLE:
3884 if (!displayExtensions.imageD3D11Texture)
3885 {
3886 val->setError(EGL_BAD_PARAMETER, message: "EGL_ANGLE_image_d3d11_texture not supported.");
3887 return false;
3888 }
3889
3890 if (context != nullptr)
3891 {
3892 val->setError(EGL_BAD_CONTEXT, message: "ctx must be EGL_NO_CONTEXT.");
3893 return false;
3894 }
3895
3896 ANGLE_EGL_TRY_RETURN(
3897 val->eglThread,
3898 display->validateImageClientBuffer(context, target, buffer, attributes),
3899 val->entryPoint, val->labeledObject, false);
3900 break;
3901
3902 case EGL_LINUX_DMA_BUF_EXT:
3903 if (!displayExtensions.imageDmaBufImportEXT)
3904 {
3905 val->setError(EGL_BAD_PARAMETER, message: "EGL_EXT_image_dma_buf_import not supported.");
3906 return false;
3907 }
3908
3909 if (context != nullptr)
3910 {
3911 val->setError(EGL_BAD_CONTEXT, message: "ctx must be EGL_NO_CONTEXT.");
3912 return false;
3913 }
3914
3915 if (buffer != nullptr)
3916 {
3917 val->setError(EGL_BAD_PARAMETER, message: "buffer must be NULL.");
3918 return false;
3919 }
3920
3921 {
3922 EGLenum kRequiredParameters[] = {EGL_WIDTH,
3923 EGL_HEIGHT,
3924 EGL_LINUX_DRM_FOURCC_EXT,
3925 EGL_DMA_BUF_PLANE0_FD_EXT,
3926 EGL_DMA_BUF_PLANE0_OFFSET_EXT,
3927 EGL_DMA_BUF_PLANE0_PITCH_EXT};
3928 for (EGLenum requiredParameter : kRequiredParameters)
3929 {
3930 if (!attributes.contains(key: requiredParameter))
3931 {
3932 val->setError(EGL_BAD_PARAMETER,
3933 message: "Missing required parameter 0x%X for image target "
3934 "EGL_LINUX_DMA_BUF_EXT.",
3935 requiredParameter);
3936 return false;
3937 }
3938 }
3939
3940 bool containPlane0ModifierLo =
3941 attributes.contains(EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT);
3942 bool containPlane0ModifierHi =
3943 attributes.contains(EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT);
3944 bool containPlane1ModifierLo =
3945 attributes.contains(EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT);
3946 bool containPlane1ModifierHi =
3947 attributes.contains(EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT);
3948 bool containPlane2ModifierLo =
3949 attributes.contains(EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT);
3950 bool containPlane2ModifierHi =
3951 attributes.contains(EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT);
3952 bool containPlane3ModifierLo =
3953 attributes.contains(EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT);
3954 bool containPlane3ModifierHi =
3955 attributes.contains(EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT);
3956 if ((containPlane0ModifierLo ^ containPlane0ModifierHi) ||
3957 (containPlane1ModifierLo ^ containPlane1ModifierHi) ||
3958 (containPlane2ModifierLo ^ containPlane2ModifierHi) ||
3959 (containPlane3ModifierLo ^ containPlane3ModifierHi))
3960 {
3961 val->setError(
3962 EGL_BAD_PARAMETER,
3963 message: "the list of attributes contains EGL_DMA_BUF_PLANE*_MODIFIER_LO_EXT "
3964 "but not EGL_DMA_BUF_PLANE*_MODIFIER_HI_EXT or vice versa.");
3965 return false;
3966 }
3967 }
3968 break;
3969
3970 case EGL_METAL_TEXTURE_ANGLE:
3971 if (!displayExtensions.mtlTextureClientBuffer)
3972 {
3973 val->setError(EGL_BAD_PARAMETER,
3974 message: "EGL_ANGLE_metal_texture_client_buffer not supported.");
3975 return false;
3976 }
3977
3978 if (context != nullptr)
3979 {
3980 val->setError(EGL_BAD_CONTEXT, message: "ctx must be EGL_NO_CONTEXT.");
3981 return false;
3982 }
3983
3984 ANGLE_EGL_TRY_RETURN(
3985 val->eglThread,
3986 display->validateImageClientBuffer(context, target, buffer, attributes),
3987 val->entryPoint, val->labeledObject, false);
3988 break;
3989 case EGL_VULKAN_IMAGE_ANGLE:
3990 if (!displayExtensions.vulkanImageANGLE)
3991 {
3992 val->setError(EGL_BAD_PARAMETER, message: "EGL_ANGLE_vulkan_image not supported.");
3993 return false;
3994 }
3995
3996 if (context != nullptr)
3997 {
3998 val->setError(EGL_BAD_CONTEXT, message: "ctx must be EGL_NO_CONTEXT.");
3999 return false;
4000 }
4001
4002 {
4003 const EGLenum kRequiredParameters[] = {
4004 EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE,
4005 EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE,
4006 };
4007 for (EGLenum requiredParameter : kRequiredParameters)
4008 {
4009 if (!attributes.contains(key: requiredParameter))
4010 {
4011 val->setError(EGL_BAD_PARAMETER,
4012 message: "Missing required parameter 0x%X for image target "
4013 "EGL_VULKAN_IMAGE_ANGLE.",
4014 requiredParameter);
4015 return false;
4016 }
4017 }
4018 }
4019
4020 ANGLE_EGL_TRY_RETURN(
4021 val->eglThread,
4022 display->validateImageClientBuffer(context, target, buffer, attributes),
4023 val->entryPoint, val->labeledObject, false);
4024 break;
4025 default:
4026 val->setError(EGL_BAD_PARAMETER, message: "invalid target: 0x%X", target);
4027 return false;
4028 }
4029
4030 if (attributes.contains(EGL_GL_TEXTURE_ZOFFSET) && target != EGL_GL_TEXTURE_3D)
4031 {
4032 val->setError(EGL_BAD_PARAMETER,
4033 message: "EGL_GL_TEXTURE_ZOFFSET must be used with a 3D texture target.");
4034 return false;
4035 }
4036
4037 return true;
4038}
4039
4040bool ValidateDestroyImage(const ValidationContext *val, const Display *display, ImageID imageID)
4041{
4042 ANGLE_VALIDATION_TRY(ValidateImage(val, display, imageID));
4043 return true;
4044}
4045
4046bool ValidateCreateImageKHR(const ValidationContext *val,
4047 const Display *display,
4048 gl::ContextID contextID,
4049 EGLenum target,
4050 EGLClientBuffer buffer,
4051 const AttributeMap &attributes)
4052{
4053 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4054
4055 if (!display->getExtensions().imageBase && !display->getExtensions().image)
4056 {
4057 // It is out of spec what happens when calling an extension function when the extension is
4058 // not available.
4059 // EGL_BAD_DISPLAY seems like a reasonable error.
4060 val->setError(EGL_BAD_DISPLAY, message: "EGL_KHR_image not supported.");
4061 return false;
4062 }
4063
4064 return ValidateCreateImage(val, display, contextID, target, buffer, attributes);
4065}
4066
4067bool ValidateDestroyImageKHR(const ValidationContext *val, const Display *display, ImageID imageID)
4068{
4069 ANGLE_VALIDATION_TRY(ValidateImage(val, display, imageID));
4070
4071 if (!display->getExtensions().imageBase && !display->getExtensions().image)
4072 {
4073 // It is out of spec what happens when calling an extension function when the extension is
4074 // not available.
4075 // EGL_BAD_DISPLAY seems like a reasonable error.
4076 val->setError(EGL_BAD_DISPLAY);
4077 return false;
4078 }
4079
4080 return true;
4081}
4082
4083bool ValidateCreateDeviceANGLE(const ValidationContext *val,
4084 EGLint device_type,
4085 const void *native_device,
4086 const EGLAttrib *attrib_list)
4087{
4088 const ClientExtensions &clientExtensions = Display::GetClientExtensions();
4089 if (!clientExtensions.deviceCreation)
4090 {
4091 val->setError(EGL_BAD_ACCESS, message: "Device creation extension not active");
4092 return false;
4093 }
4094
4095 if (attrib_list != nullptr && attrib_list[0] != EGL_NONE)
4096 {
4097 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attrib_list parameter");
4098 return false;
4099 }
4100
4101 switch (device_type)
4102 {
4103 case EGL_D3D11_DEVICE_ANGLE:
4104 if (!clientExtensions.deviceCreationD3D11)
4105 {
4106 val->setError(EGL_BAD_ATTRIBUTE, message: "D3D11 device creation extension not active");
4107 return false;
4108 }
4109 break;
4110 default:
4111 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid device_type parameter");
4112 return false;
4113 }
4114
4115 return true;
4116}
4117
4118bool ValidateReleaseDeviceANGLE(const ValidationContext *val, const Device *device)
4119{
4120 const ClientExtensions &clientExtensions = Display::GetClientExtensions();
4121 if (!clientExtensions.deviceCreation)
4122 {
4123 val->setError(EGL_BAD_ACCESS, message: "Device creation extension not active");
4124 return false;
4125 }
4126
4127 if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device))
4128 {
4129 val->setError(EGL_BAD_DEVICE_EXT, message: "Invalid device parameter");
4130 return false;
4131 }
4132
4133 Display *owningDisplay = device->getOwningDisplay();
4134 if (owningDisplay != nullptr)
4135 {
4136 val->setError(EGL_BAD_DEVICE_EXT, message: "Device must have been created using eglCreateDevice");
4137 return false;
4138 }
4139
4140 return true;
4141}
4142
4143bool ValidateCreateSync(const ValidationContext *val,
4144 const Display *display,
4145 EGLenum type,
4146 const AttributeMap &attribs)
4147{
4148 return ValidateCreateSyncBase(val, display, type, attribs, isExt: false);
4149}
4150
4151bool ValidateCreateSyncKHR(const ValidationContext *val,
4152 const Display *display,
4153 EGLenum type,
4154 const AttributeMap &attribs)
4155{
4156 return ValidateCreateSyncBase(val, display, type, attribs, isExt: true);
4157}
4158
4159bool ValidateDestroySync(const ValidationContext *val, const Display *display, SyncID sync)
4160{
4161 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
4162 return true;
4163}
4164
4165bool ValidateDestroySyncKHR(const ValidationContext *val,
4166 const Display *dpyPacked,
4167 SyncID syncPacked)
4168{
4169 return ValidateDestroySync(val, display: dpyPacked, sync: syncPacked);
4170}
4171
4172bool ValidateClientWaitSync(const ValidationContext *val,
4173 const Display *display,
4174 SyncID sync,
4175 EGLint flags,
4176 EGLTime timeout)
4177{
4178 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
4179 return true;
4180}
4181
4182bool ValidateClientWaitSyncKHR(const ValidationContext *val,
4183 const Display *dpyPacked,
4184 SyncID syncPacked,
4185 EGLint flags,
4186 EGLTimeKHR timeout)
4187{
4188 return ValidateClientWaitSync(val, display: dpyPacked, sync: syncPacked, flags, timeout);
4189}
4190
4191bool ValidateWaitSync(const ValidationContext *val,
4192 const Display *display,
4193 SyncID sync,
4194 EGLint flags)
4195{
4196 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4197
4198 const DisplayExtensions &extensions = display->getExtensions();
4199 if (!extensions.waitSync)
4200 {
4201 val->setError(EGL_BAD_ACCESS, message: "EGL_KHR_wait_sync extension is not available");
4202 return false;
4203 }
4204
4205 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
4206 ANGLE_VALIDATION_TRY(ValidateThreadContext(val, display, EGL_BAD_MATCH));
4207
4208 gl::Context *context = val->eglThread->getContext();
4209 if (!context->getExtensions().EGLSyncOES)
4210 {
4211 val->setError(EGL_BAD_MATCH,
4212 message: "Server-side waits cannot be performed without "
4213 "GL_OES_EGL_sync support.");
4214 return false;
4215 }
4216
4217 if (flags != 0)
4218 {
4219 val->setError(EGL_BAD_PARAMETER, message: "flags must be zero");
4220 return false;
4221 }
4222
4223 return true;
4224}
4225
4226bool ValidateWaitSyncKHR(const ValidationContext *val,
4227 const Display *dpyPacked,
4228 SyncID syncPacked,
4229 EGLint flags)
4230{
4231 return ValidateWaitSync(val, display: dpyPacked, sync: syncPacked, flags);
4232}
4233
4234bool ValidateGetSyncAttrib(const ValidationContext *val,
4235 const Display *display,
4236 SyncID sync,
4237 EGLint attribute,
4238 const EGLAttrib *value)
4239{
4240 if (value == nullptr)
4241 {
4242 val->setError(EGL_BAD_PARAMETER, message: "Invalid value parameter");
4243 return false;
4244 }
4245 return ValidateGetSyncAttribBase(val, display, sync, attribute);
4246}
4247
4248bool ValidateGetSyncAttribKHR(const ValidationContext *val,
4249 const Display *display,
4250 SyncID sync,
4251 EGLint attribute,
4252 const EGLint *value)
4253{
4254 if (value == nullptr)
4255 {
4256 val->setError(EGL_BAD_PARAMETER, message: "Invalid value parameter");
4257 return false;
4258 }
4259 return ValidateGetSyncAttribBase(val, display, sync, attribute);
4260}
4261
4262bool ValidateCreateStreamKHR(const ValidationContext *val,
4263 const Display *display,
4264 const AttributeMap &attributes)
4265{
4266 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4267
4268 const DisplayExtensions &displayExtensions = display->getExtensions();
4269 if (!displayExtensions.stream)
4270 {
4271 val->setError(EGL_BAD_ALLOC, message: "Stream extension not active");
4272 return false;
4273 }
4274
4275 attributes.initializeWithoutValidation();
4276
4277 for (const auto &attributeIter : attributes)
4278 {
4279 EGLAttrib attribute = attributeIter.first;
4280 EGLAttrib value = attributeIter.second;
4281
4282 ANGLE_VALIDATION_TRY(ValidateStreamAttribute(val, attribute, value, displayExtensions));
4283 }
4284
4285 return true;
4286}
4287
4288bool ValidateDestroyStreamKHR(const ValidationContext *val,
4289 const Display *display,
4290 const Stream *stream)
4291{
4292 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
4293 return true;
4294}
4295
4296bool ValidateStreamAttribKHR(const ValidationContext *val,
4297 const Display *display,
4298 const Stream *stream,
4299 EGLenum attribute,
4300 EGLint value)
4301{
4302 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
4303
4304 if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR)
4305 {
4306 val->setError(EGL_BAD_STATE_KHR, message: "Bad stream state");
4307 return false;
4308 }
4309
4310 return ValidateStreamAttribute(val, attribute, value, extensions: display->getExtensions());
4311}
4312
4313bool ValidateQueryStreamKHR(const ValidationContext *val,
4314 const Display *display,
4315 const Stream *stream,
4316 EGLenum attribute,
4317 const EGLint *value)
4318{
4319 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
4320
4321 switch (attribute)
4322 {
4323 case EGL_STREAM_STATE_KHR:
4324 case EGL_CONSUMER_LATENCY_USEC_KHR:
4325 break;
4326 case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR:
4327 if (!display->getExtensions().streamConsumerGLTexture)
4328 {
4329 val->setError(EGL_BAD_ATTRIBUTE, message: "Consumer GLTexture extension not active");
4330 return false;
4331 }
4332 break;
4333 default:
4334 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
4335 return false;
4336 }
4337
4338 return true;
4339}
4340
4341bool ValidateQueryStreamu64KHR(const ValidationContext *val,
4342 const Display *display,
4343 const Stream *stream,
4344 EGLenum attribute,
4345 const EGLuint64KHR *value)
4346{
4347 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
4348
4349 switch (attribute)
4350 {
4351 case EGL_CONSUMER_FRAME_KHR:
4352 case EGL_PRODUCER_FRAME_KHR:
4353 break;
4354 default:
4355 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
4356 return false;
4357 }
4358
4359 return true;
4360}
4361
4362bool ValidateStreamConsumerGLTextureExternalKHR(const ValidationContext *val,
4363 const Display *display,
4364 const Stream *stream)
4365{
4366 ANGLE_VALIDATION_TRY(ValidateThreadContext(val, display, EGL_BAD_CONTEXT));
4367
4368 const DisplayExtensions &displayExtensions = display->getExtensions();
4369 if (!displayExtensions.streamConsumerGLTexture)
4370 {
4371 val->setError(EGL_BAD_ACCESS, message: "Stream consumer extension not active");
4372 return false;
4373 }
4374
4375 gl::Context *context = val->eglThread->getContext();
4376 if (!context->getExtensions().EGLStreamConsumerExternalNV)
4377 {
4378 val->setError(EGL_BAD_ACCESS, message: "EGL stream consumer external GL extension not enabled");
4379 return false;
4380 }
4381
4382 if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
4383 {
4384 val->setError(EGL_BAD_STREAM_KHR, message: "Invalid stream");
4385 return false;
4386 }
4387
4388 if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR)
4389 {
4390 val->setError(EGL_BAD_STATE_KHR, message: "Invalid stream state");
4391 return false;
4392 }
4393
4394 // Lookup the texture and ensure it is correct
4395 gl::Texture *texture = context->getState().getTargetTexture(type: gl::TextureType::External);
4396 if (texture == nullptr || texture->id().value == 0)
4397 {
4398 val->setError(EGL_BAD_ACCESS, message: "No external texture bound");
4399 return false;
4400 }
4401
4402 return true;
4403}
4404
4405bool ValidateStreamConsumerAcquireKHR(const ValidationContext *val,
4406 const Display *display,
4407 const Stream *stream)
4408{
4409 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4410
4411 const DisplayExtensions &displayExtensions = display->getExtensions();
4412 if (!displayExtensions.streamConsumerGLTexture)
4413 {
4414 val->setError(EGL_BAD_ACCESS, message: "Stream consumer extension not active");
4415 return false;
4416 }
4417
4418 if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
4419 {
4420 val->setError(EGL_BAD_STREAM_KHR, message: "Invalid stream");
4421 return false;
4422 }
4423
4424 ANGLE_VALIDATION_TRY(ValidateThreadContext(val, display, EGL_BAD_CONTEXT));
4425
4426 gl::Context *context = val->eglThread->getContext();
4427 if (!stream->isConsumerBoundToContext(context))
4428 {
4429 val->setError(EGL_BAD_ACCESS, message: "Current GL context not associated with stream consumer");
4430 return false;
4431 }
4432
4433 if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB &&
4434 stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV)
4435 {
4436 val->setError(EGL_BAD_ACCESS, message: "Invalid stream consumer type");
4437 return false;
4438 }
4439
4440 // Note: technically EGL_STREAM_STATE_EMPTY_KHR is a valid state when the timeout is non-zero.
4441 // However, the timeout is effectively ignored since it has no useful functionality with the
4442 // current producers that are implemented, so we don't allow that state
4443 if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
4444 stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
4445 {
4446 val->setError(EGL_BAD_STATE_KHR, message: "Invalid stream state");
4447 return false;
4448 }
4449
4450 return true;
4451}
4452
4453bool ValidateStreamConsumerReleaseKHR(const ValidationContext *val,
4454 const Display *display,
4455 const Stream *stream)
4456{
4457 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4458
4459 const DisplayExtensions &displayExtensions = display->getExtensions();
4460 if (!displayExtensions.streamConsumerGLTexture)
4461 {
4462 val->setError(EGL_BAD_ACCESS, message: "Stream consumer extension not active");
4463 return false;
4464 }
4465
4466 if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
4467 {
4468 val->setError(EGL_BAD_STREAM_KHR, message: "Invalid stream");
4469 return false;
4470 }
4471
4472 ANGLE_VALIDATION_TRY(ValidateThreadContext(val, display, EGL_BAD_CONTEXT));
4473
4474 gl::Context *context = val->eglThread->getContext();
4475 if (!stream->isConsumerBoundToContext(context))
4476 {
4477 val->setError(EGL_BAD_ACCESS, message: "Current GL context not associated with stream consumer");
4478 return false;
4479 }
4480
4481 if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB &&
4482 stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV)
4483 {
4484 val->setError(EGL_BAD_ACCESS, message: "Invalid stream consumer type");
4485 return false;
4486 }
4487
4488 if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
4489 stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
4490 {
4491 val->setError(EGL_BAD_STATE_KHR, message: "Invalid stream state");
4492 return false;
4493 }
4494
4495 return true;
4496}
4497
4498bool ValidateStreamConsumerGLTextureExternalAttribsNV(const ValidationContext *val,
4499 const Display *display,
4500 const Stream *stream,
4501 const AttributeMap &attribs)
4502{
4503 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4504
4505 const DisplayExtensions &displayExtensions = display->getExtensions();
4506 if (!displayExtensions.streamConsumerGLTexture)
4507 {
4508 val->setError(EGL_BAD_ACCESS, message: "Stream consumer extension not active");
4509 return false;
4510 }
4511
4512 ANGLE_VALIDATION_TRY(ValidateThreadContext(val, display, EGL_BAD_CONTEXT));
4513
4514 // Although technically not a requirement in spec, the context needs to be checked for support
4515 // for external textures or future logic will cause assertions. This extension is also
4516 // effectively useless without external textures.
4517 gl::Context *context = val->eglThread->getContext();
4518 if (!context->getExtensions().EGLStreamConsumerExternalNV)
4519 {
4520 val->setError(EGL_BAD_ACCESS, message: "EGL stream consumer external GL extension not enabled");
4521 return false;
4522 }
4523
4524 if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
4525 {
4526 val->setError(EGL_BAD_STREAM_KHR, message: "Invalid stream");
4527 return false;
4528 }
4529
4530 if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR)
4531 {
4532 val->setError(EGL_BAD_STATE_KHR, message: "Invalid stream state");
4533 return false;
4534 }
4535
4536 const gl::Caps &glCaps = context->getCaps();
4537
4538 EGLAttrib colorBufferType = EGL_RGB_BUFFER;
4539 EGLAttrib planeCount = -1;
4540 EGLAttrib plane[3];
4541 for (int i = 0; i < 3; i++)
4542 {
4543 plane[i] = -1;
4544 }
4545
4546 attribs.initializeWithoutValidation();
4547
4548 for (const auto &attributeIter : attribs)
4549 {
4550 EGLAttrib attribute = attributeIter.first;
4551 EGLAttrib value = attributeIter.second;
4552
4553 switch (attribute)
4554 {
4555 case EGL_COLOR_BUFFER_TYPE:
4556 if (value != EGL_RGB_BUFFER && value != EGL_YUV_BUFFER_EXT)
4557 {
4558 val->setError(EGL_BAD_PARAMETER, message: "Invalid color buffer type");
4559 return false;
4560 }
4561 colorBufferType = value;
4562 break;
4563 case EGL_YUV_NUMBER_OF_PLANES_EXT:
4564 // planeCount = -1 is a tag for the default plane count so the value must be checked
4565 // to be positive here to ensure future logic doesn't break on invalid negative
4566 // inputs
4567 if (value < 0)
4568 {
4569 val->setError(EGL_BAD_MATCH, message: "Invalid plane count");
4570 return false;
4571 }
4572 planeCount = value;
4573 break;
4574 default:
4575 if (attribute >= EGL_YUV_PLANE0_TEXTURE_UNIT_NV &&
4576 attribute <= EGL_YUV_PLANE2_TEXTURE_UNIT_NV)
4577 {
4578 if ((value < 0 ||
4579 value >= static_cast<EGLAttrib>(glCaps.maxCombinedTextureImageUnits)) &&
4580 value != EGL_NONE)
4581 {
4582 val->setError(EGL_BAD_ACCESS, message: "Invalid texture unit");
4583 return false;
4584 }
4585 plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value;
4586 }
4587 else
4588 {
4589 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
4590 return false;
4591 }
4592 }
4593 }
4594
4595 if (colorBufferType == EGL_RGB_BUFFER)
4596 {
4597 if (planeCount > 0)
4598 {
4599 val->setError(EGL_BAD_MATCH, message: "Plane count must be 0 for RGB buffer");
4600 return false;
4601 }
4602 for (int i = 0; i < 3; i++)
4603 {
4604 if (plane[i] != -1)
4605 {
4606 val->setError(EGL_BAD_MATCH, message: "Planes cannot be specified");
4607 return false;
4608 }
4609 }
4610
4611 // Lookup the texture and ensure it is correct
4612 gl::Texture *texture = context->getState().getTargetTexture(type: gl::TextureType::External);
4613 if (texture == nullptr || texture->id().value == 0)
4614 {
4615 val->setError(EGL_BAD_ACCESS, message: "No external texture bound");
4616 return false;
4617 }
4618 }
4619 else
4620 {
4621 if (planeCount == -1)
4622 {
4623 planeCount = 2;
4624 }
4625 if (planeCount < 1 || planeCount > 3)
4626 {
4627 val->setError(EGL_BAD_MATCH, message: "Invalid YUV plane count");
4628 return false;
4629 }
4630 for (EGLAttrib i = planeCount; i < 3; i++)
4631 {
4632 if (plane[i] != -1)
4633 {
4634 val->setError(EGL_BAD_MATCH, message: "Invalid plane specified");
4635 return false;
4636 }
4637 }
4638
4639 // Set to ensure no texture is referenced more than once
4640 std::set<gl::Texture *> textureSet;
4641 for (EGLAttrib i = 0; i < planeCount; i++)
4642 {
4643 if (plane[i] == -1)
4644 {
4645 val->setError(EGL_BAD_MATCH, message: "Not all planes specified");
4646 return false;
4647 }
4648 if (plane[i] != EGL_NONE)
4649 {
4650 gl::Texture *texture = context->getState().getSamplerTexture(
4651 sampler: static_cast<unsigned int>(plane[i]), type: gl::TextureType::External);
4652 if (texture == nullptr || texture->id().value == 0)
4653 {
4654 val->setError(
4655 EGL_BAD_ACCESS,
4656 message: "No external texture bound at one or more specified texture units");
4657 return false;
4658 }
4659 if (textureSet.find(k: texture) != textureSet.end())
4660 {
4661 val->setError(EGL_BAD_ACCESS, message: "Multiple planes bound to same texture object");
4662 return false;
4663 }
4664 textureSet.insert(v: texture);
4665 }
4666 }
4667 }
4668
4669 return true;
4670}
4671
4672bool ValidateCreateStreamProducerD3DTextureANGLE(const ValidationContext *val,
4673 const Display *display,
4674 const Stream *stream,
4675 const AttributeMap &attribs)
4676{
4677 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4678
4679 const DisplayExtensions &displayExtensions = display->getExtensions();
4680 if (!displayExtensions.streamProducerD3DTexture)
4681 {
4682 val->setError(EGL_BAD_ACCESS, message: "Stream producer extension not active");
4683 return false;
4684 }
4685
4686 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
4687
4688 attribs.initializeWithoutValidation();
4689
4690 if (!attribs.isEmpty())
4691 {
4692 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
4693 return false;
4694 }
4695
4696 if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR)
4697 {
4698 val->setError(EGL_BAD_STATE_KHR, message: "Stream not in connecting state");
4699 return false;
4700 }
4701
4702 switch (stream->getConsumerType())
4703 {
4704 case Stream::ConsumerType::GLTextureYUV:
4705 if (stream->getPlaneCount() != 2)
4706 {
4707 val->setError(EGL_BAD_MATCH, message: "Incompatible stream consumer type");
4708 return false;
4709 }
4710 break;
4711
4712 case Stream::ConsumerType::GLTextureRGB:
4713 if (stream->getPlaneCount() != 1)
4714 {
4715 val->setError(EGL_BAD_MATCH, message: "Incompatible stream consumer type");
4716 return false;
4717 }
4718 break;
4719
4720 default:
4721 val->setError(EGL_BAD_MATCH, message: "Incompatible stream consumer type");
4722 return false;
4723 }
4724
4725 return true;
4726}
4727
4728bool ValidateStreamPostD3DTextureANGLE(const ValidationContext *val,
4729 const Display *display,
4730 const Stream *stream,
4731 const void *texture,
4732 const AttributeMap &attribs)
4733{
4734 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
4735
4736 const DisplayExtensions &displayExtensions = display->getExtensions();
4737 if (!displayExtensions.streamProducerD3DTexture)
4738 {
4739 val->setError(EGL_BAD_ACCESS, message: "Stream producer extension not active");
4740 return false;
4741 }
4742
4743 ANGLE_VALIDATION_TRY(ValidateStream(val, display, stream));
4744
4745 attribs.initializeWithoutValidation();
4746
4747 for (auto &attributeIter : attribs)
4748 {
4749 EGLAttrib attribute = attributeIter.first;
4750 EGLAttrib value = attributeIter.second;
4751
4752 switch (attribute)
4753 {
4754 case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE:
4755 if (value < 0)
4756 {
4757 val->setError(EGL_BAD_PARAMETER, message: "Invalid subresource index");
4758 return false;
4759 }
4760 break;
4761 case EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG:
4762 if (value < 0)
4763 {
4764 val->setError(EGL_BAD_PARAMETER, message: "Invalid plane offset");
4765 return false;
4766 }
4767 break;
4768 default:
4769 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid attribute");
4770 return false;
4771 }
4772 }
4773
4774 if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR &&
4775 stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
4776 stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
4777 {
4778 val->setError(EGL_BAD_STATE_KHR, message: "Stream not fully configured");
4779 return false;
4780 }
4781
4782 if (stream->getProducerType() != Stream::ProducerType::D3D11Texture)
4783 {
4784 val->setError(EGL_BAD_MATCH, message: "Incompatible stream producer");
4785 return false;
4786 }
4787
4788 if (texture == nullptr)
4789 {
4790 val->setError(EGL_BAD_PARAMETER, message: "Texture is null");
4791 return false;
4792 }
4793
4794 ANGLE_EGL_TRY_RETURN(val->eglThread, stream->validateD3D11Texture(texture, attribs),
4795 val->entryPoint, val->labeledObject, false);
4796
4797 return true;
4798}
4799
4800bool ValidateSyncControlCHROMIUM(const ValidationContext *val,
4801 const Display *display,
4802 SurfaceID surfaceID)
4803{
4804 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
4805
4806 const DisplayExtensions &displayExtensions = display->getExtensions();
4807 if (!displayExtensions.syncControlCHROMIUM)
4808 {
4809 val->setError(EGL_BAD_ACCESS, message: "syncControlCHROMIUM extension not active");
4810 return false;
4811 }
4812
4813 return true;
4814}
4815
4816bool ValidateSyncControlRateANGLE(const ValidationContext *val,
4817 const Display *display,
4818 SurfaceID surfaceID)
4819{
4820 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
4821
4822 const DisplayExtensions &displayExtensions = display->getExtensions();
4823 if (!displayExtensions.syncControlRateANGLE)
4824 {
4825 val->setError(EGL_BAD_ACCESS, message: "syncControlRateANGLE extension not active");
4826 return false;
4827 }
4828
4829 return true;
4830}
4831
4832bool ValidateGetMscRateANGLE(const ValidationContext *val,
4833 const Display *display,
4834 SurfaceID surfaceID,
4835 const EGLint *numerator,
4836 const EGLint *denominator)
4837{
4838 ANGLE_VALIDATION_TRY(ValidateSyncControlRateANGLE(val, display, surfaceID));
4839
4840 if (numerator == nullptr)
4841 {
4842 val->setError(EGL_BAD_PARAMETER, message: "numerator is null");
4843 return false;
4844 }
4845 if (denominator == nullptr)
4846 {
4847 val->setError(EGL_BAD_PARAMETER, message: "denominator is null");
4848 return false;
4849 }
4850
4851 return true;
4852}
4853
4854bool ValidateGetSyncValuesCHROMIUM(const ValidationContext *val,
4855 const Display *display,
4856 SurfaceID surfaceID,
4857 const EGLuint64KHR *ust,
4858 const EGLuint64KHR *msc,
4859 const EGLuint64KHR *sbc)
4860{
4861 ANGLE_VALIDATION_TRY(ValidateSyncControlCHROMIUM(val, display, surfaceID));
4862
4863 if (ust == nullptr)
4864 {
4865 val->setError(EGL_BAD_PARAMETER, message: "ust is null");
4866 return false;
4867 }
4868 if (msc == nullptr)
4869 {
4870 val->setError(EGL_BAD_PARAMETER, message: "msc is null");
4871 return false;
4872 }
4873 if (sbc == nullptr)
4874 {
4875 val->setError(EGL_BAD_PARAMETER, message: "sbc is null");
4876 return false;
4877 }
4878
4879 return true;
4880}
4881
4882bool ValidateDestroySurface(const ValidationContext *val,
4883 const Display *display,
4884 SurfaceID surfaceID)
4885{
4886 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
4887 return true;
4888}
4889
4890bool ValidateDestroyContext(const ValidationContext *val,
4891 const Display *display,
4892 gl::ContextID contextID)
4893{
4894 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
4895 return true;
4896}
4897
4898bool ValidateSwapBuffers(const ValidationContext *val, const Display *display, SurfaceID surfaceID)
4899{
4900 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
4901
4902 if (display->isDeviceLost())
4903 {
4904 val->setError(EGL_CONTEXT_LOST);
4905 return false;
4906 }
4907
4908 const Surface *eglSurface = display->getSurface(surfaceID);
4909 if (eglSurface->isLocked())
4910 {
4911 val->setError(EGL_BAD_ACCESS);
4912 return false;
4913 }
4914
4915 if (eglSurface == EGL_NO_SURFACE || !val->eglThread->getContext() ||
4916 val->eglThread->getCurrentDrawSurface() != eglSurface)
4917 {
4918 val->setError(EGL_BAD_SURFACE);
4919 return false;
4920 }
4921
4922 return true;
4923}
4924
4925bool ValidateSwapBuffersWithDamageKHR(const ValidationContext *val,
4926 const Display *display,
4927 SurfaceID surfaceID,
4928 const EGLint *rects,
4929 EGLint n_rects)
4930{
4931 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
4932
4933 if (!display->getExtensions().swapBuffersWithDamage)
4934 {
4935 // It is out of spec what happens when calling an extension function when the extension is
4936 // not available. EGL_BAD_DISPLAY seems like a reasonable error.
4937 val->setError(EGL_BAD_DISPLAY, message: "EGL_KHR_swap_buffers_with_damage is not available.");
4938 return false;
4939 }
4940
4941 const Surface *surface = display->getSurface(surfaceID);
4942 if (surface == nullptr)
4943 {
4944 val->setError(EGL_BAD_SURFACE, message: "Swap surface cannot be EGL_NO_SURFACE.");
4945 return false;
4946 }
4947
4948 if (n_rects < 0)
4949 {
4950 val->setError(EGL_BAD_PARAMETER, message: "n_rects cannot be negative.");
4951 return false;
4952 }
4953
4954 if (n_rects > 0 && rects == nullptr)
4955 {
4956 val->setError(EGL_BAD_PARAMETER, message: "n_rects cannot be greater than zero when rects is NULL.");
4957 return false;
4958 }
4959
4960 if (surface->isLocked())
4961 {
4962 val->setError(EGL_BAD_ACCESS);
4963 return false;
4964 }
4965
4966 // TODO(jmadill): Validate Surface is bound to the thread.
4967
4968 return true;
4969}
4970
4971bool ValidateWaitNative(const ValidationContext *val, const EGLint engine)
4972{
4973 if (val->eglThread->getDisplay() == nullptr)
4974 {
4975 // EGL spec says this about eglWaitNative -
4976 // eglWaitNative is ignored if there is no current EGL rendering context.
4977 return true;
4978 }
4979
4980 ANGLE_VALIDATION_TRY(ValidateDisplay(val, val->eglThread->getDisplay()));
4981
4982 if (engine != EGL_CORE_NATIVE_ENGINE)
4983 {
4984 val->setError(EGL_BAD_PARAMETER, message: "the 'engine' parameter has an unrecognized value");
4985 return false;
4986 }
4987
4988 return true;
4989}
4990
4991bool ValidateCopyBuffers(const ValidationContext *val,
4992 const Display *display,
4993 SurfaceID surfaceID,
4994 EGLNativePixmapType target)
4995{
4996 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
4997
4998 if (display->isDeviceLost())
4999 {
5000 val->setError(EGL_CONTEXT_LOST);
5001 return false;
5002 }
5003
5004 return true;
5005}
5006
5007bool ValidateBindTexImage(const ValidationContext *val,
5008 const Display *display,
5009 SurfaceID surfaceID,
5010 const EGLint buffer)
5011{
5012 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5013
5014 if (buffer != EGL_BACK_BUFFER)
5015 {
5016 val->setError(EGL_BAD_PARAMETER);
5017 return false;
5018 }
5019
5020 const Surface *surface = display->getSurface(surfaceID);
5021 if (surface->getType() == EGL_WINDOW_BIT)
5022 {
5023 val->setError(EGL_BAD_SURFACE);
5024 return false;
5025 }
5026
5027 if (surface->getBoundTexture())
5028 {
5029 val->setError(EGL_BAD_ACCESS);
5030 return false;
5031 }
5032
5033 if (surface->getTextureFormat() == TextureFormat::NoTexture)
5034 {
5035 val->setError(EGL_BAD_MATCH);
5036 return false;
5037 }
5038
5039 if (surface->isLocked())
5040 {
5041 val->setError(EGL_BAD_ACCESS);
5042 return false;
5043 }
5044
5045 gl::Context *context = val->eglThread->getContext();
5046 if (context && !context->isContextLost())
5047 {
5048 gl::TextureType type = egl_gl::EGLTextureTargetToTextureType(eglTarget: surface->getTextureTarget());
5049 gl::Texture *textureObject = context->getTextureByType(type);
5050 ASSERT(textureObject != nullptr);
5051
5052 if (textureObject->getImmutableFormat())
5053 {
5054 val->setError(EGL_BAD_MATCH);
5055 return false;
5056 }
5057 }
5058
5059 return true;
5060}
5061
5062bool ValidateReleaseTexImage(const ValidationContext *val,
5063 const Display *display,
5064 SurfaceID surfaceID,
5065 const EGLint buffer)
5066{
5067 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5068
5069 if (buffer != EGL_BACK_BUFFER)
5070 {
5071 val->setError(EGL_BAD_PARAMETER);
5072 return false;
5073 }
5074
5075 const Surface *surface = display->getSurface(surfaceID);
5076 if (surface->getType() == EGL_WINDOW_BIT)
5077 {
5078 val->setError(EGL_BAD_SURFACE);
5079 return false;
5080 }
5081
5082 if (surface->getTextureFormat() == TextureFormat::NoTexture)
5083 {
5084 val->setError(EGL_BAD_MATCH);
5085 return false;
5086 }
5087
5088 return true;
5089}
5090
5091bool ValidateSwapInterval(const ValidationContext *val, const Display *display, EGLint interval)
5092{
5093 ANGLE_VALIDATION_TRY(ValidateThreadContext(val, display, EGL_BAD_CONTEXT));
5094
5095 Surface *drawSurface = val->eglThread->getCurrentDrawSurface();
5096 if (drawSurface == nullptr)
5097 {
5098 val->setError(EGL_BAD_SURFACE);
5099 return false;
5100 }
5101
5102 return true;
5103}
5104
5105bool ValidateBindAPI(const ValidationContext *val, const EGLenum api)
5106{
5107 switch (api)
5108 {
5109 case EGL_OPENGL_ES_API:
5110 case EGL_OPENGL_API:
5111 break;
5112 case EGL_OPENVG_API:
5113 val->setError(EGL_BAD_PARAMETER);
5114 return false; // Not supported by this implementation
5115 default:
5116 val->setError(EGL_BAD_PARAMETER);
5117 return false;
5118 }
5119
5120 return true;
5121}
5122
5123bool ValidatePresentationTimeANDROID(const ValidationContext *val,
5124 const Display *display,
5125 SurfaceID surfaceID,
5126 EGLnsecsANDROID time)
5127{
5128 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5129
5130 if (!display->getExtensions().presentationTime)
5131 {
5132 // It is out of spec what happens when calling an extension function when the extension is
5133 // not available. EGL_BAD_DISPLAY seems like a reasonable error.
5134 val->setError(EGL_BAD_DISPLAY, message: "EGL_ANDROID_presentation_time is not available.");
5135 return false;
5136 }
5137
5138 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5139
5140 return true;
5141}
5142
5143bool ValidateSetBlobCacheFuncsANDROID(const ValidationContext *val,
5144 const Display *display,
5145 EGLSetBlobFuncANDROID set,
5146 EGLGetBlobFuncANDROID get)
5147{
5148 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5149
5150 if (display->areBlobCacheFuncsSet())
5151 {
5152 val->setError(EGL_BAD_PARAMETER,
5153 message: "Blob cache functions can only be set once in the lifetime of a Display");
5154 return false;
5155 }
5156
5157 if (set == nullptr || get == nullptr)
5158 {
5159 val->setError(EGL_BAD_PARAMETER, message: "Blob cache callbacks cannot be null.");
5160 return false;
5161 }
5162
5163 return true;
5164}
5165
5166bool ValidateGetConfigAttrib(const ValidationContext *val,
5167 const Display *display,
5168 const Config *config,
5169 EGLint attribute,
5170 const EGLint *value)
5171{
5172 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, config));
5173 ANGLE_TRY(ValidateConfigAttribute(val, display, static_cast<EGLAttrib>(attribute)));
5174 return true;
5175}
5176
5177bool ValidateChooseConfig(const ValidationContext *val,
5178 const Display *display,
5179 const AttributeMap &attribs,
5180 const EGLConfig *configs,
5181 EGLint configSize,
5182 const EGLint *numConfig)
5183{
5184 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5185 ANGLE_VALIDATION_TRY(ValidateConfigAttributes(val, display, attribs));
5186
5187 if (numConfig == nullptr)
5188 {
5189 val->setError(EGL_BAD_PARAMETER, message: "num_config cannot be null.");
5190 return false;
5191 }
5192
5193 return true;
5194}
5195
5196bool ValidateGetConfigs(const ValidationContext *val,
5197 const Display *display,
5198 const EGLConfig *configs,
5199 EGLint configSize,
5200 const EGLint *numConfig)
5201{
5202 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5203
5204 if (numConfig == nullptr)
5205 {
5206 val->setError(EGL_BAD_PARAMETER, message: "num_config cannot be null.");
5207 return false;
5208 }
5209
5210 return true;
5211}
5212
5213bool ValidateGetPlatformDisplay(const ValidationContext *val,
5214 EGLenum platform,
5215 const void *native_display,
5216 const AttributeMap &attribMap)
5217{
5218 return ValidateGetPlatformDisplayCommon(val, platform, native_display, attribMap);
5219}
5220
5221bool ValidateGetPlatformDisplayEXT(const ValidationContext *val,
5222 EGLenum platform,
5223 const void *native_display,
5224 const AttributeMap &attribMap)
5225{
5226 return ValidateGetPlatformDisplayCommon(val, platform, native_display, attribMap);
5227}
5228
5229bool ValidateCreatePlatformWindowSurfaceEXT(const ValidationContext *val,
5230 const Display *display,
5231 const Config *configuration,
5232 const void *nativeWindow,
5233 const AttributeMap &attributes)
5234{
5235 if (!Display::GetClientExtensions().platformBase)
5236 {
5237 val->setError(EGL_BAD_ACCESS, message: "EGL_EXT_platform_base not supported");
5238 return false;
5239 }
5240
5241 const void *actualNativeWindow = display->getImplementation()->isX11()
5242 ? *reinterpret_cast<const void *const *>(nativeWindow)
5243 : nativeWindow;
5244
5245 return ValidateCreatePlatformWindowSurface(val, dpyPacked: display, configPacked: configuration, native_window: actualNativeWindow,
5246 attrib_listPacked: attributes);
5247}
5248
5249bool ValidateCreatePlatformPixmapSurfaceEXT(const ValidationContext *val,
5250 const Display *display,
5251 const Config *configuration,
5252 const void *nativePixmap,
5253 const AttributeMap &attributes)
5254{
5255 if (!Display::GetClientExtensions().platformBase)
5256 {
5257 val->setError(EGL_BAD_ACCESS, message: "EGL_EXT_platform_base not supported");
5258 return false;
5259 }
5260
5261 ANGLE_VALIDATION_TRY(ValidateConfig(val, display, configuration));
5262
5263 val->setError(EGL_BAD_DISPLAY, message: "ValidateCreatePlatformPixmapSurfaceEXT unimplemented.");
5264 return false;
5265}
5266
5267bool ValidateProgramCacheGetAttribANGLE(const ValidationContext *val,
5268 const Display *display,
5269 EGLenum attrib)
5270{
5271 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5272
5273 if (!display->getExtensions().programCacheControlANGLE)
5274 {
5275 val->setError(EGL_BAD_ACCESS, message: "Extension not supported");
5276 return false;
5277 }
5278
5279 switch (attrib)
5280 {
5281 case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
5282 case EGL_PROGRAM_CACHE_SIZE_ANGLE:
5283 break;
5284
5285 default:
5286 val->setError(EGL_BAD_PARAMETER, message: "Invalid program cache attribute.");
5287 return false;
5288 }
5289
5290 return true;
5291}
5292
5293bool ValidateProgramCacheQueryANGLE(const ValidationContext *val,
5294 const Display *display,
5295 EGLint index,
5296 const void *key,
5297 const EGLint *keysize,
5298 const void *binary,
5299 const EGLint *binarysize)
5300{
5301 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5302
5303 if (!display->getExtensions().programCacheControlANGLE)
5304 {
5305 val->setError(EGL_BAD_ACCESS, message: "Extension not supported");
5306 return false;
5307 }
5308
5309 if (index < 0 || index >= display->programCacheGetAttrib(EGL_PROGRAM_CACHE_SIZE_ANGLE))
5310 {
5311 val->setError(EGL_BAD_PARAMETER, message: "Program index out of range.");
5312 return false;
5313 }
5314
5315 if (keysize == nullptr || binarysize == nullptr)
5316 {
5317 val->setError(EGL_BAD_PARAMETER, message: "keysize and binarysize must always be valid pointers.");
5318 return false;
5319 }
5320
5321 if (binary && *keysize != static_cast<EGLint>(egl::BlobCache::kKeyLength))
5322 {
5323 val->setError(EGL_BAD_PARAMETER, message: "Invalid program key size.");
5324 return false;
5325 }
5326
5327 if ((key == nullptr) != (binary == nullptr))
5328 {
5329 val->setError(EGL_BAD_PARAMETER, message: "key and binary must both be null or both non-null.");
5330 return false;
5331 }
5332
5333 return true;
5334}
5335
5336bool ValidateProgramCachePopulateANGLE(const ValidationContext *val,
5337 const Display *display,
5338 const void *key,
5339 EGLint keysize,
5340 const void *binary,
5341 EGLint binarysize)
5342{
5343 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5344
5345 if (!display->getExtensions().programCacheControlANGLE)
5346 {
5347 val->setError(EGL_BAD_ACCESS, message: "Extension not supported");
5348 return false;
5349 }
5350
5351 if (keysize != static_cast<EGLint>(egl::BlobCache::kKeyLength))
5352 {
5353 val->setError(EGL_BAD_PARAMETER, message: "Invalid program key size.");
5354 return false;
5355 }
5356
5357 if (key == nullptr || binary == nullptr)
5358 {
5359 val->setError(EGL_BAD_PARAMETER, message: "null pointer in arguments.");
5360 return false;
5361 }
5362
5363 // Upper bound for binarysize is arbitrary.
5364 if (binarysize <= 0 || binarysize > egl::kProgramCacheSizeAbsoluteMax)
5365 {
5366 val->setError(EGL_BAD_PARAMETER, message: "binarysize out of valid range.");
5367 return false;
5368 }
5369
5370 return true;
5371}
5372
5373bool ValidateProgramCacheResizeANGLE(const ValidationContext *val,
5374 const Display *display,
5375 EGLint limit,
5376 EGLint mode)
5377{
5378 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5379
5380 if (!display->getExtensions().programCacheControlANGLE)
5381 {
5382 val->setError(EGL_BAD_ACCESS, message: "Extension not supported");
5383 return false;
5384 }
5385
5386 if (limit < 0)
5387 {
5388 val->setError(EGL_BAD_PARAMETER, message: "limit must be non-negative.");
5389 return false;
5390 }
5391
5392 switch (mode)
5393 {
5394 case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
5395 case EGL_PROGRAM_CACHE_TRIM_ANGLE:
5396 break;
5397
5398 default:
5399 val->setError(EGL_BAD_PARAMETER, message: "Invalid cache resize mode.");
5400 return false;
5401 }
5402
5403 return true;
5404}
5405
5406bool ValidateSurfaceAttrib(const ValidationContext *val,
5407 const Display *display,
5408 SurfaceID surfaceID,
5409 EGLint attribute,
5410 EGLint value)
5411{
5412 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5413 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5414
5415 const Surface *surface = display->getSurface(surfaceID);
5416 if (surface == EGL_NO_SURFACE)
5417 {
5418 val->setError(EGL_BAD_SURFACE, message: "Surface cannot be EGL_NO_SURFACE.");
5419 return false;
5420 }
5421
5422 switch (attribute)
5423 {
5424 case EGL_MIPMAP_LEVEL:
5425 break;
5426
5427 case EGL_MULTISAMPLE_RESOLVE:
5428 switch (value)
5429 {
5430 case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
5431 break;
5432
5433 case EGL_MULTISAMPLE_RESOLVE_BOX:
5434 if ((surface->getConfig()->surfaceType & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) == 0)
5435 {
5436 val->setError(EGL_BAD_MATCH,
5437 message: "Surface does not support EGL_MULTISAMPLE_RESOLVE_BOX.");
5438 return false;
5439 }
5440 break;
5441
5442 default:
5443 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid multisample resolve type.");
5444 return false;
5445 }
5446 break;
5447
5448 case EGL_SWAP_BEHAVIOR:
5449 switch (value)
5450 {
5451 case EGL_BUFFER_PRESERVED:
5452 if ((surface->getConfig()->surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == 0)
5453 {
5454 val->setError(EGL_BAD_MATCH,
5455 message: "Surface does not support EGL_SWAP_BEHAVIOR_PRESERVED.");
5456 return false;
5457 }
5458 break;
5459
5460 case EGL_BUFFER_DESTROYED:
5461 break;
5462
5463 default:
5464 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid swap behaviour.");
5465 return false;
5466 }
5467 break;
5468
5469 case EGL_WIDTH:
5470 case EGL_HEIGHT:
5471 if (!display->getExtensions().windowFixedSize)
5472 {
5473 val->setError(EGL_BAD_ATTRIBUTE,
5474 message: "EGL_WIDTH or EGL_HEIGHT cannot be set without "
5475 "EGL_ANGLE_window_fixed_size support.");
5476 return false;
5477 }
5478 if (!surface->isFixedSize())
5479 {
5480 val->setError(EGL_BAD_MATCH,
5481 message: "EGL_WIDTH or EGL_HEIGHT cannot be set without "
5482 "EGL_FIXED_SIZE_ANGLE being enabled on the surface.");
5483 return false;
5484 }
5485 break;
5486
5487 case EGL_TIMESTAMPS_ANDROID:
5488 if (!display->getExtensions().getFrameTimestamps &&
5489 !display->getExtensions().timestampSurfaceAttributeANGLE)
5490 {
5491 val->setError(EGL_BAD_ATTRIBUTE,
5492 message: "EGL_TIMESTAMPS_ANDROID cannot be used without "
5493 "EGL_ANDROID_get_frame_timestamps support.");
5494 return false;
5495 }
5496 switch (value)
5497 {
5498 case EGL_TRUE:
5499 case EGL_FALSE:
5500 break;
5501
5502 default:
5503 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid value.");
5504 return false;
5505 }
5506 break;
5507
5508 case EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID:
5509 ASSERT(value == EGL_TRUE || value == EGL_FALSE);
5510 break;
5511
5512 case EGL_RENDER_BUFFER:
5513 if (value != EGL_BACK_BUFFER && value != EGL_SINGLE_BUFFER)
5514 {
5515 val->setError(EGL_BAD_ATTRIBUTE,
5516 message: "EGL_RENDER_BUFFER must be EGL_BACK_BUFFER or EGL_SINGLE_BUFFER.");
5517 return false;
5518 }
5519
5520 if (value == EGL_SINGLE_BUFFER)
5521 {
5522 if (!display->getExtensions().mutableRenderBufferKHR)
5523 {
5524 val->setError(
5525 EGL_BAD_ATTRIBUTE,
5526 message: "Attribute EGL_RENDER_BUFFER requires EGL_KHR_mutable_render_buffer.");
5527 return false;
5528 }
5529
5530 if ((surface->getConfig()->surfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR) == 0)
5531 {
5532 val->setError(EGL_BAD_MATCH,
5533 message: "EGL_RENDER_BUFFER requires the surface type bit "
5534 "EGL_MUTABLE_RENDER_BUFFER_BIT_KHR.");
5535 return false;
5536 }
5537 }
5538 break;
5539
5540 default:
5541 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid surface attribute: 0x%04X", attribute);
5542 return false;
5543 }
5544
5545 return true;
5546}
5547
5548bool ValidateQuerySurface(const ValidationContext *val,
5549 const Display *display,
5550 SurfaceID surfaceID,
5551 EGLint attribute,
5552 const EGLint *value)
5553{
5554 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5555 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5556
5557 const Surface *surface = display->getSurface(surfaceID);
5558 if (surface == EGL_NO_SURFACE)
5559 {
5560 val->setError(EGL_BAD_SURFACE, message: "Surface cannot be EGL_NO_SURFACE.");
5561 return false;
5562 }
5563
5564 switch (attribute)
5565 {
5566 case EGL_GL_COLORSPACE:
5567 case EGL_VG_ALPHA_FORMAT:
5568 case EGL_VG_COLORSPACE:
5569 case EGL_CONFIG_ID:
5570 case EGL_HEIGHT:
5571 case EGL_HORIZONTAL_RESOLUTION:
5572 case EGL_LARGEST_PBUFFER:
5573 case EGL_MIPMAP_TEXTURE:
5574 case EGL_MIPMAP_LEVEL:
5575 case EGL_MULTISAMPLE_RESOLVE:
5576 case EGL_PIXEL_ASPECT_RATIO:
5577 case EGL_RENDER_BUFFER:
5578 case EGL_SWAP_BEHAVIOR:
5579 case EGL_TEXTURE_FORMAT:
5580 case EGL_TEXTURE_TARGET:
5581 case EGL_VERTICAL_RESOLUTION:
5582 case EGL_WIDTH:
5583 break;
5584
5585 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
5586 if (!display->getExtensions().postSubBuffer)
5587 {
5588 val->setError(EGL_BAD_ATTRIBUTE,
5589 message: "EGL_POST_SUB_BUFFER_SUPPORTED_NV cannot be used "
5590 "without EGL_ANGLE_surface_orientation support.");
5591 return false;
5592 }
5593 break;
5594
5595 case EGL_FIXED_SIZE_ANGLE:
5596 if (!display->getExtensions().windowFixedSize)
5597 {
5598 val->setError(EGL_BAD_ATTRIBUTE,
5599 message: "EGL_FIXED_SIZE_ANGLE cannot be used without "
5600 "EGL_ANGLE_window_fixed_size support.");
5601 return false;
5602 }
5603 break;
5604
5605 case EGL_SURFACE_ORIENTATION_ANGLE:
5606 if (!display->getExtensions().surfaceOrientation)
5607 {
5608 val->setError(EGL_BAD_ATTRIBUTE,
5609 message: "EGL_SURFACE_ORIENTATION_ANGLE cannot be "
5610 "queried without "
5611 "EGL_ANGLE_surface_orientation support.");
5612 return false;
5613 }
5614 break;
5615
5616 case EGL_DIRECT_COMPOSITION_ANGLE:
5617 if (!display->getExtensions().directComposition)
5618 {
5619 val->setError(EGL_BAD_ATTRIBUTE,
5620 message: "EGL_DIRECT_COMPOSITION_ANGLE cannot be "
5621 "used without "
5622 "EGL_ANGLE_direct_composition support.");
5623 return false;
5624 }
5625 break;
5626
5627 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
5628 if (!display->getExtensions().robustResourceInitializationANGLE)
5629 {
5630 val->setError(EGL_BAD_ATTRIBUTE,
5631 message: "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be "
5632 "used without EGL_ANGLE_robust_resource_initialization "
5633 "support.");
5634 return false;
5635 }
5636 break;
5637
5638 case EGL_TIMESTAMPS_ANDROID:
5639 if (!display->getExtensions().getFrameTimestamps &&
5640 !display->getExtensions().timestampSurfaceAttributeANGLE)
5641 {
5642 val->setError(EGL_BAD_ATTRIBUTE,
5643 message: "EGL_TIMESTAMPS_ANDROID cannot be used without "
5644 "EGL_ANDROID_get_frame_timestamps support.");
5645 return false;
5646 }
5647 break;
5648
5649 case EGL_BUFFER_AGE_EXT:
5650 {
5651 if (!display->getExtensions().bufferAgeEXT)
5652 {
5653 val->setError(EGL_BAD_ATTRIBUTE,
5654 message: "EGL_BUFFER_AGE_EXT cannot be used without "
5655 "EGL_EXT_buffer_age support.");
5656 return false;
5657 }
5658 gl::Context *context = val->eglThread->getContext();
5659 if ((context == nullptr) || (context->getCurrentDrawSurface() != surface))
5660 {
5661 val->setError(EGL_BAD_SURFACE,
5662 message: "The surface must be current to the current context "
5663 "in order to query buffer age per extension "
5664 "EGL_EXT_buffer_age.");
5665 return false;
5666 }
5667 }
5668 break;
5669
5670 case EGL_BITMAP_PITCH_KHR:
5671 case EGL_BITMAP_ORIGIN_KHR:
5672 case EGL_BITMAP_PIXEL_RED_OFFSET_KHR:
5673 case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR:
5674 case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR:
5675 case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR:
5676 case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR:
5677 case EGL_BITMAP_PIXEL_SIZE_KHR:
5678 if (!display->getExtensions().lockSurface3KHR)
5679 {
5680 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_KHR_lock_surface3 is not supported.");
5681 return false;
5682 }
5683 break;
5684
5685 case EGL_PROTECTED_CONTENT_EXT:
5686 if (!display->getExtensions().protectedContentEXT)
5687 {
5688 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_EXT_protected_content not supported");
5689 return false;
5690 }
5691 break;
5692
5693 default:
5694 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid surface attribute: 0x%04X", attribute);
5695 return false;
5696 }
5697
5698 return true;
5699}
5700
5701bool ValidateQueryContext(const ValidationContext *val,
5702 const Display *display,
5703 gl::ContextID contextID,
5704 EGLint attribute,
5705 const EGLint *value)
5706{
5707 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
5708
5709 switch (attribute)
5710 {
5711 case EGL_CONFIG_ID:
5712 case EGL_CONTEXT_CLIENT_TYPE:
5713 case EGL_CONTEXT_CLIENT_VERSION:
5714 case EGL_RENDER_BUFFER:
5715 break;
5716
5717 case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
5718 if (!display->getExtensions().robustResourceInitializationANGLE)
5719 {
5720 val->setError(EGL_BAD_ATTRIBUTE,
5721 message: "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be "
5722 "used without EGL_ANGLE_robust_resource_initialization "
5723 "support.");
5724 return false;
5725 }
5726 break;
5727
5728 case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
5729 if (!display->getExtensions().contextPriority)
5730 {
5731 val->setError(EGL_BAD_ATTRIBUTE,
5732 message: "Attribute EGL_CONTEXT_PRIORITY_LEVEL_IMG requires "
5733 "extension EGL_IMG_context_priority.");
5734 return false;
5735 }
5736 break;
5737
5738 case EGL_PROTECTED_CONTENT_EXT:
5739 if (!display->getExtensions().protectedContentEXT)
5740 {
5741 val->setError(EGL_BAD_ATTRIBUTE, message: "EGL_EXT_protected_content not supported");
5742 return false;
5743 }
5744 break;
5745
5746 default:
5747 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid context attribute: 0x%04X", attribute);
5748 return false;
5749 }
5750
5751 return true;
5752}
5753
5754bool ValidateDebugMessageControlKHR(const ValidationContext *val,
5755 EGLDEBUGPROCKHR callback,
5756 const AttributeMap &attribs)
5757{
5758 const ClientExtensions &clientExtensions = Display::GetClientExtensions();
5759 if (!clientExtensions.debug)
5760 {
5761 val->setError(EGL_BAD_ACCESS, message: "EGL_KHR_debug extension is not available.");
5762 return false;
5763 }
5764
5765 attribs.initializeWithoutValidation();
5766
5767 for (const auto &attrib : attribs)
5768 {
5769 switch (attrib.first)
5770 {
5771 case EGL_DEBUG_MSG_CRITICAL_KHR:
5772 case EGL_DEBUG_MSG_ERROR_KHR:
5773 case EGL_DEBUG_MSG_WARN_KHR:
5774 case EGL_DEBUG_MSG_INFO_KHR:
5775 if (attrib.second != EGL_TRUE && attrib.second != EGL_FALSE)
5776 {
5777 val->setError(EGL_BAD_ATTRIBUTE,
5778 message: "message controls must be EGL_TRUE or EGL_FALSE.");
5779 return false;
5780 }
5781 break;
5782 }
5783 }
5784
5785 return true;
5786}
5787
5788bool ValidateQueryDebugKHR(const ValidationContext *val, EGLint attribute, const EGLAttrib *value)
5789{
5790 const ClientExtensions &clientExtensions = Display::GetClientExtensions();
5791 if (!clientExtensions.debug)
5792 {
5793 val->setError(EGL_BAD_ACCESS, message: "EGL_KHR_debug extension is not available.");
5794 return false;
5795 }
5796
5797 switch (attribute)
5798 {
5799 case EGL_DEBUG_MSG_CRITICAL_KHR:
5800 case EGL_DEBUG_MSG_ERROR_KHR:
5801 case EGL_DEBUG_MSG_WARN_KHR:
5802 case EGL_DEBUG_MSG_INFO_KHR:
5803 case EGL_DEBUG_CALLBACK_KHR:
5804 break;
5805
5806 default:
5807 val->setError(EGL_BAD_ATTRIBUTE, message: "Unknown attribute: 0x%04X", attribute);
5808 return false;
5809 }
5810
5811 return true;
5812}
5813
5814bool ValidateLabelObjectKHR(const ValidationContext *val,
5815 const Display *display,
5816 ObjectType objectType,
5817 EGLObjectKHR object,
5818 EGLLabelKHR label)
5819{
5820 const ClientExtensions &clientExtensions = Display::GetClientExtensions();
5821 if (!clientExtensions.debug)
5822 {
5823 val->setError(EGL_BAD_ACCESS, message: "EGL_KHR_debug extension is not available.");
5824 return false;
5825 }
5826
5827 const LabeledObject *labeledObject = nullptr;
5828 ANGLE_VALIDATION_TRY(ValidateLabeledObject(val, display, objectType, object, &labeledObject));
5829
5830 return true;
5831}
5832
5833bool ValidateGetCompositorTimingSupportedANDROID(const ValidationContext *val,
5834 const Display *display,
5835 SurfaceID surfaceID,
5836 CompositorTiming name)
5837{
5838 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5839
5840 if (!display->getExtensions().getFrameTimestamps)
5841 {
5842 val->setError(EGL_BAD_DISPLAY,
5843 message: "EGL_ANDROID_get_frame_timestamps extension is not available.");
5844 return false;
5845 }
5846
5847 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5848
5849 if (!ValidCompositorTimingName(name))
5850 {
5851 val->setError(EGL_BAD_PARAMETER, message: "invalid timing name.");
5852 return false;
5853 }
5854
5855 return true;
5856}
5857
5858bool ValidateGetCompositorTimingANDROID(const ValidationContext *val,
5859 const Display *display,
5860 SurfaceID surfaceID,
5861 EGLint numTimestamps,
5862 const EGLint *names,
5863 const EGLnsecsANDROID *values)
5864{
5865 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5866
5867 if (!display->getExtensions().getFrameTimestamps)
5868 {
5869 val->setError(EGL_BAD_DISPLAY,
5870 message: "EGL_ANDROID_get_frame_timestamps extension is not available.");
5871 return false;
5872 }
5873
5874 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5875
5876 if (names == nullptr && numTimestamps > 0)
5877 {
5878 val->setError(EGL_BAD_PARAMETER, message: "names is NULL.");
5879 return false;
5880 }
5881
5882 if (values == nullptr && numTimestamps > 0)
5883 {
5884 val->setError(EGL_BAD_PARAMETER, message: "values is NULL.");
5885 return false;
5886 }
5887
5888 if (numTimestamps < 0)
5889 {
5890 val->setError(EGL_BAD_PARAMETER, message: "numTimestamps must be at least 0.");
5891 return false;
5892 }
5893
5894 for (EGLint i = 0; i < numTimestamps; i++)
5895 {
5896 CompositorTiming name = FromEGLenum<CompositorTiming>(from: names[i]);
5897
5898 if (!ValidCompositorTimingName(name))
5899 {
5900 val->setError(EGL_BAD_PARAMETER, message: "invalid compositor timing.");
5901 return false;
5902 }
5903
5904 const Surface *surface = display->getSurface(surfaceID);
5905 if (!surface->getSupportedCompositorTimings().test(pos: name))
5906 {
5907 val->setError(EGL_BAD_PARAMETER, message: "compositor timing not supported by surface.");
5908 return false;
5909 }
5910 }
5911
5912 return true;
5913}
5914
5915bool ValidateGetNextFrameIdANDROID(const ValidationContext *val,
5916 const Display *display,
5917 SurfaceID surfaceID,
5918 const EGLuint64KHR *frameId)
5919{
5920 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5921
5922 if (!display->getExtensions().getFrameTimestamps)
5923 {
5924 val->setError(EGL_BAD_DISPLAY,
5925 message: "EGL_ANDROID_get_frame_timestamps extension is not available.");
5926 return false;
5927 }
5928
5929 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5930
5931 if (frameId == nullptr)
5932 {
5933 val->setError(EGL_BAD_PARAMETER, message: "frameId is NULL.");
5934 return false;
5935 }
5936
5937 return true;
5938}
5939
5940bool ValidateGetFrameTimestampSupportedANDROID(const ValidationContext *val,
5941 const Display *display,
5942 SurfaceID surfaceID,
5943 Timestamp timestamp)
5944{
5945 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5946
5947 if (!display->getExtensions().getFrameTimestamps)
5948 {
5949 val->setError(EGL_BAD_DISPLAY,
5950 message: "EGL_ANDROID_get_frame_timestamps extension is not available.");
5951 return false;
5952 }
5953
5954 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5955
5956 if (!ValidTimestampType(timestamp))
5957 {
5958 val->setError(EGL_BAD_PARAMETER, message: "invalid timestamp type.");
5959 return false;
5960 }
5961
5962 return true;
5963}
5964
5965bool ValidateGetFrameTimestampsANDROID(const ValidationContext *val,
5966 const Display *display,
5967 SurfaceID surfaceID,
5968 EGLuint64KHR frameId,
5969 EGLint numTimestamps,
5970 const EGLint *timestamps,
5971 const EGLnsecsANDROID *values)
5972{
5973 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
5974
5975 if (!display->getExtensions().getFrameTimestamps)
5976 {
5977 val->setError(EGL_BAD_DISPLAY,
5978 message: "EGL_ANDROID_get_frame_timestamps extension is not available.");
5979 return false;
5980 }
5981
5982 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
5983
5984 const Surface *surface = display->getSurface(surfaceID);
5985 if (!surface->isTimestampsEnabled())
5986 {
5987 val->setError(EGL_BAD_SURFACE, message: "timestamp collection is not enabled for this surface.");
5988 return false;
5989 }
5990
5991 if (timestamps == nullptr && numTimestamps > 0)
5992 {
5993 val->setError(EGL_BAD_PARAMETER, message: "timestamps is NULL.");
5994 return false;
5995 }
5996
5997 if (values == nullptr && numTimestamps > 0)
5998 {
5999 val->setError(EGL_BAD_PARAMETER, message: "values is NULL.");
6000 return false;
6001 }
6002
6003 if (numTimestamps < 0)
6004 {
6005 val->setError(EGL_BAD_PARAMETER, message: "numTimestamps must be at least 0.");
6006 return false;
6007 }
6008
6009 for (EGLint i = 0; i < numTimestamps; i++)
6010 {
6011 Timestamp timestamp = FromEGLenum<Timestamp>(from: timestamps[i]);
6012
6013 if (!ValidTimestampType(timestamp))
6014 {
6015 val->setError(EGL_BAD_PARAMETER, message: "invalid timestamp type.");
6016 return false;
6017 }
6018
6019 if (!surface->getSupportedTimestamps().test(pos: timestamp))
6020 {
6021 val->setError(EGL_BAD_PARAMETER, message: "timestamp not supported by surface.");
6022 return false;
6023 }
6024 }
6025
6026 return true;
6027}
6028
6029bool ValidateQueryStringiANGLE(const ValidationContext *val,
6030 const Display *display,
6031 EGLint name,
6032 EGLint index)
6033{
6034 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6035
6036 if (!Display::GetClientExtensions().featureControlANGLE)
6037 {
6038 val->setError(EGL_BAD_DISPLAY, message: "EGL_ANGLE_feature_control extension is not available.");
6039 return false;
6040 }
6041
6042 if (index < 0)
6043 {
6044 val->setError(EGL_BAD_PARAMETER, message: "index is negative.");
6045 return false;
6046 }
6047
6048 switch (name)
6049 {
6050 case EGL_FEATURE_NAME_ANGLE:
6051 case EGL_FEATURE_CATEGORY_ANGLE:
6052 case EGL_FEATURE_DESCRIPTION_ANGLE:
6053 case EGL_FEATURE_BUG_ANGLE:
6054 case EGL_FEATURE_STATUS_ANGLE:
6055 case EGL_FEATURE_CONDITION_ANGLE:
6056 break;
6057 default:
6058 val->setError(EGL_BAD_PARAMETER, message: "name is not valid.");
6059 return false;
6060 }
6061
6062 if (static_cast<size_t>(index) >= display->getFeatures().size())
6063 {
6064 val->setError(EGL_BAD_PARAMETER, message: "index is too big.");
6065 return false;
6066 }
6067
6068 return true;
6069}
6070
6071bool ValidateQueryDisplayAttribEXT(const ValidationContext *val,
6072 const Display *display,
6073 const EGLint attribute,
6074 const EGLAttrib *value)
6075{
6076 ANGLE_VALIDATION_TRY(ValidateQueryDisplayAttribBase(val, display, attribute));
6077 return true;
6078}
6079
6080bool ValidateQueryDisplayAttribANGLE(const ValidationContext *val,
6081 const Display *display,
6082 const EGLint attribute,
6083 const EGLAttrib *value)
6084{
6085 ANGLE_VALIDATION_TRY(ValidateQueryDisplayAttribBase(val, display, attribute));
6086 return true;
6087}
6088
6089bool ValidateGetNativeClientBufferANDROID(const ValidationContext *val,
6090 const AHardwareBuffer *buffer)
6091{
6092 // No extension check is done because no display is passed to eglGetNativeClientBufferANDROID
6093 // despite it being a display extension. No display is needed for the implementation though.
6094 if (buffer == nullptr)
6095 {
6096 val->setError(EGL_BAD_PARAMETER, message: "NULL buffer.");
6097 return false;
6098 }
6099
6100 return true;
6101}
6102
6103bool ValidateCreateNativeClientBufferANDROID(const ValidationContext *val,
6104 const egl::AttributeMap &attribMap)
6105{
6106 attribMap.initializeWithoutValidation();
6107
6108 if (attribMap.isEmpty() || attribMap.begin()->second == EGL_NONE)
6109 {
6110 val->setError(EGL_BAD_PARAMETER, message: "invalid attribute list.");
6111 return false;
6112 }
6113
6114 int width = attribMap.getAsInt(EGL_WIDTH, defaultValue: 0);
6115 int height = attribMap.getAsInt(EGL_HEIGHT, defaultValue: 0);
6116 int redSize = attribMap.getAsInt(EGL_RED_SIZE, defaultValue: 0);
6117 int greenSize = attribMap.getAsInt(EGL_GREEN_SIZE, defaultValue: 0);
6118 int blueSize = attribMap.getAsInt(EGL_BLUE_SIZE, defaultValue: 0);
6119 int alphaSize = attribMap.getAsInt(EGL_ALPHA_SIZE, defaultValue: 0);
6120 int usage = attribMap.getAsInt(EGL_NATIVE_BUFFER_USAGE_ANDROID, defaultValue: 0);
6121
6122 for (AttributeMap::const_iterator attributeIter = attribMap.begin();
6123 attributeIter != attribMap.end(); attributeIter++)
6124 {
6125 EGLAttrib attribute = attributeIter->first;
6126 switch (attribute)
6127 {
6128 case EGL_WIDTH:
6129 case EGL_HEIGHT:
6130 // Validation done after the switch statement
6131 break;
6132 case EGL_RED_SIZE:
6133 case EGL_GREEN_SIZE:
6134 case EGL_BLUE_SIZE:
6135 case EGL_ALPHA_SIZE:
6136 if (redSize < 0 || greenSize < 0 || blueSize < 0 || alphaSize < 0)
6137 {
6138 val->setError(EGL_BAD_PARAMETER, message: "incorrect channel size requested");
6139 return false;
6140 }
6141 break;
6142 case EGL_NATIVE_BUFFER_USAGE_ANDROID:
6143 // The buffer must be used for either a texture or a renderbuffer.
6144 if ((usage & ~(EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID |
6145 EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID |
6146 EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID)) != 0)
6147 {
6148 val->setError(EGL_BAD_PARAMETER, message: "invalid usage flag");
6149 return false;
6150 }
6151 break;
6152 case EGL_NONE:
6153 break;
6154 default:
6155 val->setError(EGL_BAD_ATTRIBUTE, message: "invalid attribute");
6156 return false;
6157 }
6158 }
6159
6160 // Validate EGL_WIDTH and EGL_HEIGHT values passed in. Done here to account
6161 // for the case where EGL_WIDTH and EGL_HEIGHT were not part of the attribute list.
6162 if (width <= 0 || height <= 0)
6163 {
6164 val->setError(EGL_BAD_PARAMETER, message: "incorrect buffer dimensions requested");
6165 return false;
6166 }
6167
6168 if (gl::GetAndroidHardwareBufferFormatFromChannelSizes(attribMap) == 0)
6169 {
6170 val->setError(EGL_BAD_PARAMETER, message: "unsupported format");
6171 return false;
6172 }
6173 return true;
6174}
6175
6176bool ValidateCopyMetalSharedEventANGLE(const ValidationContext *val,
6177 const Display *display,
6178 SyncID sync)
6179{
6180 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6181
6182 if (!display->getExtensions().mtlSyncSharedEventANGLE)
6183 {
6184 val->setError(EGL_BAD_DISPLAY, message: "EGL_ANGLE_metal_shared_event_sync is not available.");
6185 return false;
6186 }
6187
6188 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
6189
6190 return true;
6191}
6192
6193bool ValidateDupNativeFenceFDANDROID(const ValidationContext *val,
6194 const Display *display,
6195 SyncID sync)
6196{
6197 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6198
6199 if (!display->getExtensions().nativeFenceSyncANDROID)
6200 {
6201 val->setError(EGL_BAD_DISPLAY, message: "EGL_ANDROID_native_fence_sync extension is not available.");
6202 return false;
6203 }
6204
6205 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
6206
6207 return true;
6208}
6209
6210bool ValidateSwapBuffersWithFrameTokenANGLE(const ValidationContext *val,
6211 const Display *display,
6212 SurfaceID surfaceID,
6213 EGLFrameTokenANGLE frametoken)
6214{
6215 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6216
6217 if (!display->getExtensions().swapWithFrameToken)
6218 {
6219 val->setError(EGL_BAD_DISPLAY, message: "EGL_ANGLE_swap_buffers_with_frame_token is not available.");
6220 return false;
6221 }
6222
6223 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
6224
6225 return true;
6226}
6227
6228bool ValidatePrepareSwapBuffersANGLE(const ValidationContext *val,
6229 const Display *display,
6230 SurfaceID surfaceID)
6231{
6232 return ValidateSwapBuffers(val, display, surfaceID);
6233}
6234
6235bool ValidateSignalSyncKHR(const ValidationContext *val,
6236 const Display *display,
6237 SyncID sync,
6238 EGLenum mode)
6239{
6240 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6241
6242 ANGLE_VALIDATION_TRY(ValidateSync(val, display, sync));
6243
6244 const Sync *syncObj = display->getSync(syncID: sync);
6245
6246 if (syncObj->getType() == EGL_SYNC_REUSABLE_KHR)
6247 {
6248 if (!display->getExtensions().reusableSyncKHR)
6249 {
6250 val->setError(EGL_BAD_MATCH, message: "EGL_KHR_reusable_sync extension is not available.");
6251 return false;
6252 }
6253
6254 if ((mode != EGL_SIGNALED_KHR) && (mode != EGL_UNSIGNALED_KHR))
6255 {
6256 val->setError(EGL_BAD_PARAMETER, message: "eglSignalSyncKHR invalid mode.");
6257 return false;
6258 }
6259
6260 return true;
6261 }
6262
6263 val->setError(EGL_BAD_MATCH);
6264 return false;
6265}
6266
6267bool ValidateQuerySurfacePointerANGLE(const ValidationContext *val,
6268 const Display *display,
6269 SurfaceID surfaceID,
6270 EGLint attribute,
6271 void *const *value)
6272{
6273 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6274
6275 if (!display->getExtensions().querySurfacePointer)
6276 {
6277 val->setError(EGL_BAD_ACCESS);
6278 return false;
6279 }
6280
6281 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
6282
6283 // validate the attribute parameter
6284 switch (attribute)
6285 {
6286 case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
6287 if (!display->getExtensions().surfaceD3DTexture2DShareHandle)
6288 {
6289 val->setError(EGL_BAD_ATTRIBUTE);
6290 return false;
6291 }
6292 break;
6293 case EGL_DXGI_KEYED_MUTEX_ANGLE:
6294 if (!display->getExtensions().keyedMutex)
6295 {
6296 val->setError(EGL_BAD_ATTRIBUTE);
6297 return false;
6298 }
6299 break;
6300 default:
6301 val->setError(EGL_BAD_ATTRIBUTE);
6302 return false;
6303 }
6304
6305 return true;
6306}
6307
6308bool ValidatePostSubBufferNV(const ValidationContext *val,
6309 const Display *display,
6310 SurfaceID surfaceID,
6311 EGLint x,
6312 EGLint y,
6313 EGLint width,
6314 EGLint height)
6315{
6316 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6317
6318 if (!display->getExtensions().postSubBuffer)
6319 {
6320 val->setError(EGL_BAD_ACCESS);
6321 return false;
6322 }
6323
6324 if (x < 0 || y < 0 || width < 0 || height < 0)
6325 {
6326 val->setError(EGL_BAD_PARAMETER);
6327 return false;
6328 }
6329
6330 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
6331
6332 if (display->isDeviceLost())
6333 {
6334 val->setError(EGL_CONTEXT_LOST);
6335 return false;
6336 }
6337
6338 return true;
6339}
6340
6341bool ValidateQueryDeviceAttribEXT(const ValidationContext *val,
6342 const Device *device,
6343 EGLint attribute,
6344 const EGLAttrib *value)
6345{
6346 ANGLE_VALIDATION_TRY(ValidateDevice(val, device));
6347
6348 if (!Display::GetClientExtensions().deviceQueryEXT)
6349 {
6350 val->setError(EGL_BAD_ACCESS, message: "EGL_EXT_device_query not supported.");
6351 return false;
6352 }
6353
6354 // validate the attribute parameter
6355 switch (attribute)
6356 {
6357 case EGL_D3D11_DEVICE_ANGLE:
6358 case EGL_D3D9_DEVICE_ANGLE:
6359 if (!device->getExtensions().deviceD3D || device->getType() != attribute)
6360 {
6361 val->setError(EGL_BAD_ATTRIBUTE);
6362 return false;
6363 }
6364 break;
6365 case EGL_EAGL_CONTEXT_ANGLE:
6366 if (!device->getExtensions().deviceEAGL)
6367 {
6368 val->setError(EGL_BAD_ATTRIBUTE);
6369 return false;
6370 }
6371 break;
6372 case EGL_METAL_DEVICE_ANGLE:
6373 if (!device->getExtensions().deviceMetal)
6374 {
6375 val->setError(EGL_BAD_ATTRIBUTE);
6376 return false;
6377 }
6378 break;
6379 case EGL_VULKAN_VERSION_ANGLE:
6380 case EGL_VULKAN_INSTANCE_ANGLE:
6381 case EGL_VULKAN_INSTANCE_EXTENSIONS_ANGLE:
6382 case EGL_VULKAN_PHYSICAL_DEVICE_ANGLE:
6383 case EGL_VULKAN_DEVICE_ANGLE:
6384 case EGL_VULKAN_DEVICE_EXTENSIONS_ANGLE:
6385 case EGL_VULKAN_FEATURES_ANGLE:
6386 case EGL_VULKAN_QUEUE_ANGLE:
6387 case EGL_VULKAN_QUEUE_FAMILIY_INDEX_ANGLE:
6388 case EGL_VULKAN_GET_INSTANCE_PROC_ADDR:
6389 if (!device->getExtensions().deviceVulkan)
6390 {
6391 val->setError(EGL_BAD_ATTRIBUTE);
6392 return false;
6393 }
6394 break;
6395 case EGL_CGL_CONTEXT_ANGLE:
6396 case EGL_CGL_PIXEL_FORMAT_ANGLE:
6397 if (!device->getExtensions().deviceCGL)
6398 {
6399 val->setError(EGL_BAD_ATTRIBUTE);
6400 return false;
6401 }
6402 break;
6403 default:
6404 val->setError(EGL_BAD_ATTRIBUTE);
6405 return false;
6406 }
6407 return true;
6408}
6409
6410bool ValidateQueryDeviceStringEXT(const ValidationContext *val, const Device *device, EGLint name)
6411{
6412 ANGLE_VALIDATION_TRY(ValidateDevice(val, device));
6413 return true;
6414}
6415
6416bool ValidateReleaseHighPowerGPUANGLE(const ValidationContext *val,
6417 const Display *display,
6418 gl::ContextID contextID)
6419{
6420 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
6421 return true;
6422}
6423
6424bool ValidateReacquireHighPowerGPUANGLE(const ValidationContext *val,
6425 const Display *display,
6426 gl::ContextID contextID)
6427{
6428 ANGLE_VALIDATION_TRY(ValidateContext(val, display, contextID));
6429 return true;
6430}
6431
6432bool ValidateHandleGPUSwitchANGLE(const ValidationContext *val, const Display *display)
6433{
6434 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6435 return true;
6436}
6437
6438bool ValidateForceGPUSwitchANGLE(const ValidationContext *val,
6439 const Display *display,
6440 EGLint gpuIDHigh,
6441 EGLint gpuIDLow)
6442{
6443 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6444 return true;
6445}
6446
6447bool ValidateWaitUntilWorkScheduledANGLE(const ValidationContext *val, const Display *display)
6448{
6449 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6450 return true;
6451}
6452
6453bool ValidateGetCurrentDisplay(const ValidationContext *val)
6454{
6455 return true;
6456}
6457
6458bool ValidateGetCurrentSurface(const ValidationContext *val, EGLint readdraw)
6459{
6460 switch (readdraw)
6461 {
6462 case EGL_READ:
6463 case EGL_DRAW:
6464 return true;
6465
6466 default:
6467 val->setError(EGL_BAD_PARAMETER, message: "Invalid surface type");
6468 return false;
6469 }
6470}
6471
6472bool ValidateGetDisplay(const ValidationContext *val, EGLNativeDisplayType display_id)
6473{
6474 return true;
6475}
6476
6477bool ValidateGetError(const ValidationContext *val)
6478{
6479 return true;
6480}
6481
6482bool ValidateGetProcAddress(const ValidationContext *val, const char *procname)
6483{
6484 return true;
6485}
6486
6487bool ValidateQueryString(const ValidationContext *val, const Display *dpyPacked, EGLint name)
6488{
6489 // The only situation where EGL_NO_DISPLAY is allowed is when querying
6490 // EGL_EXTENSIONS or EGL_VERSION.
6491 const bool canQueryWithoutDisplay = (name == EGL_VERSION || name == EGL_EXTENSIONS);
6492
6493 if (dpyPacked != nullptr || !canQueryWithoutDisplay)
6494 {
6495 ANGLE_VALIDATION_TRY(ValidateDisplay(val, dpyPacked));
6496 }
6497
6498 switch (name)
6499 {
6500 case EGL_CLIENT_APIS:
6501 case EGL_EXTENSIONS:
6502 case EGL_VENDOR:
6503 case EGL_VERSION:
6504 break;
6505 default:
6506 val->setError(EGL_BAD_PARAMETER);
6507 return false;
6508 }
6509 return true;
6510}
6511
6512bool ValidateWaitGL(const ValidationContext *val)
6513{
6514 if (val->eglThread->getDisplay() == nullptr)
6515 {
6516 // EGL spec says this about eglWaitGL -
6517 // eglWaitGL is ignored if there is no current EGL rendering context for OpenGL ES.
6518 return true;
6519 }
6520
6521 ANGLE_VALIDATION_TRY(ValidateDisplay(val, val->eglThread->getDisplay()));
6522 return true;
6523}
6524
6525bool ValidateQueryAPI(const ValidationContext *val)
6526{
6527 return true;
6528}
6529
6530bool ValidateReleaseThread(const ValidationContext *val)
6531{
6532 return true;
6533}
6534
6535bool ValidateWaitClient(const ValidationContext *val)
6536{
6537 if (val->eglThread->getDisplay() == nullptr)
6538 {
6539 // EGL spec says this about eglWaitClient -
6540 // If there is no current context for the current rendering API,
6541 // the function has no effect but still returns EGL_TRUE.
6542 return true;
6543 }
6544
6545 ANGLE_VALIDATION_TRY(ValidateDisplay(val, val->eglThread->getDisplay()));
6546 return true;
6547}
6548
6549bool ValidateGetCurrentContext(const ValidationContext *val)
6550{
6551 return true;
6552}
6553
6554bool ValidateCreatePlatformPixmapSurface(const ValidationContext *val,
6555 const Display *dpyPacked,
6556 const Config *configPacked,
6557 const void *native_pixmap,
6558 const AttributeMap &attrib_listPacked)
6559{
6560 EGLNativePixmapType nativePixmap =
6561 reinterpret_cast<EGLNativePixmapType>(const_cast<void *>(native_pixmap));
6562 return ValidateCreatePixmapSurface(val, display: dpyPacked, config: configPacked, pixmap: nativePixmap,
6563 attributes: attrib_listPacked);
6564}
6565
6566bool ValidateCreatePlatformWindowSurface(const ValidationContext *val,
6567 const Display *dpyPacked,
6568 const Config *configPacked,
6569 const void *native_window,
6570 const AttributeMap &attrib_listPacked)
6571{
6572 EGLNativeWindowType nativeWindow =
6573 reinterpret_cast<EGLNativeWindowType>(const_cast<void *>(native_window));
6574 return ValidateCreateWindowSurface(val, display: dpyPacked, config: configPacked, window: nativeWindow,
6575 attributes: attrib_listPacked);
6576}
6577
6578bool ValidateLockSurfaceKHR(const ValidationContext *val,
6579 const egl::Display *dpy,
6580 SurfaceID surfaceID,
6581 const AttributeMap &attributes)
6582{
6583 ANGLE_VALIDATION_TRY(ValidateDisplay(val, dpy));
6584 ANGLE_VALIDATION_TRY(ValidateSurface(val, dpy, surfaceID));
6585
6586 if (!dpy->getExtensions().lockSurface3KHR)
6587 {
6588 val->setError(EGL_BAD_ACCESS);
6589 return false;
6590 }
6591
6592 const Surface *surface = dpy->getSurface(surfaceID);
6593 if (surface->isLocked())
6594 {
6595 val->setError(EGL_BAD_ACCESS);
6596 return false;
6597 }
6598
6599 if ((surface->getConfig()->surfaceType & EGL_LOCK_SURFACE_BIT_KHR) == false)
6600 {
6601 val->setError(EGL_BAD_ACCESS, message: "Config does not support EGL_LOCK_SURFACE_BIT");
6602 return false;
6603 }
6604
6605 if (surface->isCurrentOnAnyContext())
6606 {
6607 val->setError(EGL_BAD_ACCESS,
6608 message: "Surface cannot be current to a context for eglLockSurface()");
6609 return false;
6610 }
6611
6612 if (surface->hasProtectedContent())
6613 {
6614 val->setError(EGL_BAD_ACCESS, message: "Surface cannot be protected content for eglLockSurface()");
6615 return false;
6616 }
6617
6618 attributes.initializeWithoutValidation();
6619
6620 for (const auto &attributeIter : attributes)
6621 {
6622 EGLAttrib attribute = attributeIter.first;
6623 EGLAttrib value = attributeIter.second;
6624
6625 switch (attribute)
6626 {
6627 case EGL_MAP_PRESERVE_PIXELS_KHR:
6628 if (!((value == EGL_FALSE) || (value == EGL_TRUE)))
6629 {
6630 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid EGL_MAP_PRESERVE_PIXELS_KHR value");
6631 return false;
6632 }
6633 break;
6634 case EGL_LOCK_USAGE_HINT_KHR:
6635 if ((value & (EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR)) != value)
6636 {
6637 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid EGL_LOCK_USAGE_HINT_KHR value");
6638 return false;
6639 }
6640 break;
6641 default:
6642 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid query surface64 attribute");
6643 return false;
6644 }
6645 }
6646
6647 return true;
6648}
6649
6650bool ValidateQuerySurface64KHR(const ValidationContext *val,
6651 const egl::Display *dpy,
6652 SurfaceID surfaceID,
6653 EGLint attribute,
6654 const EGLAttribKHR *value)
6655{
6656 ANGLE_VALIDATION_TRY(ValidateDisplay(val, dpy));
6657 ANGLE_VALIDATION_TRY(ValidateSurface(val, dpy, surfaceID));
6658
6659 if (!dpy->getExtensions().lockSurface3KHR)
6660 {
6661 val->setError(EGL_BAD_ACCESS);
6662 return false;
6663 }
6664
6665 switch (attribute)
6666 {
6667 case EGL_BITMAP_PITCH_KHR:
6668 case EGL_BITMAP_ORIGIN_KHR:
6669 case EGL_BITMAP_PIXEL_RED_OFFSET_KHR:
6670 case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR:
6671 case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR:
6672 case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR:
6673 case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR:
6674 case EGL_BITMAP_PIXEL_SIZE_KHR:
6675 case EGL_BITMAP_POINTER_KHR:
6676 break;
6677 default:
6678 val->setError(EGL_BAD_ATTRIBUTE, message: "Invalid eglQuerySurface64 attribute");
6679 return false;
6680 }
6681
6682 if (value == nullptr)
6683 {
6684 val->setError(EGL_BAD_PARAMETER, message: "value is NULL.");
6685 return false;
6686 }
6687
6688 const Surface *surface = dpy->getSurface(surfaceID);
6689 if (!surface->isLocked())
6690 {
6691 val->setError(EGL_BAD_ACCESS, message: "Surface is not locked");
6692 return false;
6693 }
6694
6695 return true;
6696}
6697
6698bool ValidateUnlockSurfaceKHR(const ValidationContext *val,
6699 const egl::Display *dpy,
6700 SurfaceID surfaceID)
6701{
6702 ANGLE_VALIDATION_TRY(ValidateDisplay(val, dpy));
6703 ANGLE_VALIDATION_TRY(ValidateSurface(val, dpy, surfaceID));
6704
6705 if (!dpy->getExtensions().lockSurface3KHR)
6706 {
6707 val->setError(EGL_BAD_ACCESS);
6708 return false;
6709 }
6710
6711 const Surface *surface = dpy->getSurface(surfaceID);
6712 if (!surface->isLocked())
6713 {
6714 val->setError(EGL_BAD_PARAMETER, message: "Surface is not locked.");
6715 return false;
6716 }
6717
6718 return true;
6719}
6720
6721bool ValidateExportVkImageANGLE(const ValidationContext *val,
6722 const Display *dpy,
6723 ImageID imageID,
6724 const void *vkImage,
6725 const void *vkImageCreateInfo)
6726{
6727 ANGLE_VALIDATION_TRY(ValidateImage(val, dpy, imageID));
6728
6729 if (!dpy->getExtensions().vulkanImageANGLE)
6730 {
6731 val->setError(EGL_BAD_ACCESS);
6732 return false;
6733 }
6734
6735 if (!vkImage)
6736 {
6737 val->setError(EGL_BAD_PARAMETER, message: "Output VkImage pointer is null.");
6738 return false;
6739 }
6740
6741 if (!vkImageCreateInfo)
6742 {
6743 val->setError(EGL_BAD_PARAMETER, message: "Output VkImageCreateInfo pointer is null.");
6744 return false;
6745 }
6746
6747 return true;
6748}
6749
6750bool ValidateSetDamageRegionKHR(const ValidationContext *val,
6751 const Display *display,
6752 SurfaceID surfaceID,
6753 const EGLint *rects,
6754 EGLint n_rects)
6755{
6756 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6757 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, surfaceID));
6758
6759 const Surface *surface = display->getSurface(surfaceID);
6760 if (!(surface->getType() & EGL_WINDOW_BIT))
6761 {
6762 val->setError(EGL_BAD_MATCH, message: "surface is not a postable surface");
6763 return false;
6764 }
6765
6766 if (surface != val->eglThread->getCurrentDrawSurface())
6767 {
6768 val->setError(EGL_BAD_MATCH,
6769 message: "surface is not the current draw surface for the calling thread");
6770 return false;
6771 }
6772
6773 if (surface->getSwapBehavior() != EGL_BUFFER_DESTROYED)
6774 {
6775 val->setError(EGL_BAD_MATCH, message: "surface's swap behavior is not EGL_BUFFER_DESTROYED");
6776 return false;
6777 }
6778
6779 if (surface->isDamageRegionSet())
6780 {
6781 val->setError(
6782 EGL_BAD_ACCESS,
6783 message: "damage region has already been set on surface since the most recent frame boundary");
6784 return false;
6785 }
6786
6787 if (!surface->bufferAgeQueriedSinceLastSwap())
6788 {
6789 val->setError(EGL_BAD_ACCESS,
6790 message: "EGL_BUFFER_AGE_KHR attribute of surface has not been queried since the most "
6791 "recent frame boundary");
6792 return false;
6793 }
6794
6795 return true;
6796}
6797
6798bool ValidateQueryDmaBufFormatsEXT(ValidationContext const *val,
6799 Display const *dpy,
6800 EGLint max_formats,
6801 const EGLint *formats,
6802 const EGLint *num_formats)
6803{
6804 ANGLE_VALIDATION_TRY(ValidateDisplay(val, dpy));
6805
6806 if (!dpy->getExtensions().imageDmaBufImportModifiersEXT)
6807 {
6808 val->setError(EGL_BAD_ACCESS, message: "EGL_EXT_dma_buf_import_modfier not supported");
6809 return false;
6810 }
6811
6812 if (max_formats < 0)
6813 {
6814 val->setError(EGL_BAD_PARAMETER, message: "max_formats should not be negative");
6815 return false;
6816 }
6817
6818 if (max_formats > 0 && formats == nullptr)
6819 {
6820 val->setError(EGL_BAD_PARAMETER, message: "if max_formats is positive, formats should not be NULL");
6821 return false;
6822 }
6823
6824 return true;
6825}
6826
6827bool ValidateQueryDmaBufModifiersEXT(ValidationContext const *val,
6828 Display const *dpy,
6829 EGLint format,
6830 EGLint max_modifiers,
6831 const EGLuint64KHR *modifiers,
6832 const EGLBoolean *external_only,
6833 const EGLint *num_modifiers)
6834{
6835 ANGLE_VALIDATION_TRY(ValidateDisplay(val, dpy));
6836
6837 if (!dpy->getExtensions().imageDmaBufImportModifiersEXT)
6838 {
6839 val->setError(EGL_BAD_ACCESS, message: "EGL_EXT_dma_buf_import_modfier not supported");
6840 return false;
6841 }
6842
6843 if (max_modifiers < 0)
6844 {
6845 val->setError(EGL_BAD_PARAMETER, message: "max_modifiers should not be negative");
6846 return false;
6847 }
6848
6849 if (max_modifiers > 0 && modifiers == nullptr)
6850 {
6851 val->setError(EGL_BAD_PARAMETER,
6852 message: "if max_modifiers is positive, modifiers should not be NULL");
6853 return false;
6854 }
6855
6856 if (!dpy->supportsDmaBufFormat(format))
6857 {
6858 val->setError(EGL_BAD_PARAMETER,
6859 message: "format should be one of the formats advertised by QueryDmaBufFormatsEXT");
6860 return false;
6861 }
6862 return true;
6863}
6864
6865bool ValidateAcquireExternalContextANGLE(const ValidationContext *val,
6866 const egl::Display *display,
6867 SurfaceID drawAndReadPacked)
6868{
6869 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6870 ANGLE_VALIDATION_TRY(ValidateSurface(val, display, drawAndReadPacked));
6871
6872 const DisplayExtensions &displayExtensions = display->getExtensions();
6873 if (!displayExtensions.externalContextAndSurface)
6874 {
6875 val->setError(EGL_BAD_ACCESS, message: "EGL_ANGLE_external_context_and_surface is not available");
6876 return false;
6877 }
6878
6879 gl::Context *currentContext = val->eglThread->getContext();
6880 if (currentContext == nullptr || !currentContext->isExternal())
6881 {
6882 val->setError(EGL_BAD_CONTEXT, message: "Current context is not an external context");
6883 return false;
6884 }
6885
6886 return true;
6887}
6888
6889bool ValidateReleaseExternalContextANGLE(const ValidationContext *val, const egl::Display *display)
6890{
6891 ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
6892
6893 const DisplayExtensions &displayExtensions = display->getExtensions();
6894 if (!displayExtensions.externalContextAndSurface)
6895 {
6896 val->setError(EGL_BAD_ACCESS, message: "EGL_ANGLE_external_context_and_surface is not available");
6897 return false;
6898 }
6899
6900 gl::Context *currentContext = val->eglThread->getContext();
6901 if (currentContext == nullptr || !currentContext->isExternal())
6902 {
6903 val->setError(EGL_BAD_CONTEXT, message: "Current context is not an external context");
6904 return false;
6905 }
6906
6907 return true;
6908}
6909} // namespace egl
6910

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/third_party/angle/src/libANGLE/validationEGL.cpp