diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/validationEGL.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 2013 |
1 files changed, 1726 insertions, 287 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp index 903f51b158..13a3a9e280 100644 --- a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -14,10 +14,15 @@ #include "libANGLE/Device.h" #include "libANGLE/Display.h" #include "libANGLE/Image.h" +#include "libANGLE/Stream.h" #include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" #include <EGL/eglext.h> +namespace egl +{ namespace { size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) @@ -30,6 +35,9 @@ size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) case GL_TEXTURE_2D: maxDimension = caps.max2DTextureSize; break; + case GL_TEXTURE_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; case GL_TEXTURE_CUBE_MAP: maxDimension = caps.maxCubeMapTextureSize; break; @@ -56,7 +64,7 @@ bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::T for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { - if (texture->getInternalFormat(face, level) != GL_NONE) + if (texture->getFormat(face, level).valid()) { return true; } @@ -64,7 +72,7 @@ bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::T } else { - if (texture->getInternalFormat(texture->getTarget(), level) != GL_NONE) + if (texture->getFormat(texture->getTarget(), level).valid()) { return true; } @@ -79,7 +87,7 @@ bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture) ASSERT(texture->getTarget() == GL_TEXTURE_CUBE_MAP); for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { - if (texture->getInternalFormat(face, 0) == GL_NONE) + if (!texture->getFormat(face, 0).valid()) { return true; } @@ -87,114 +95,482 @@ bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture) return false; } + +Error ValidateStreamAttribute(const EGLAttrib attribute, + const EGLAttrib value, + const DisplayExtensions &extensions) +{ + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + case EGL_PRODUCER_FRAME_KHR: + case EGL_CONSUMER_FRAME_KHR: + return EglBadAccess() << "Attempt to initialize readonly parameter"; + case EGL_CONSUMER_LATENCY_USEC_KHR: + // Technically not in spec but a latency < 0 makes no sense so we check it + if (value < 0) + { + return EglBadParameter() << "Latency must be positive"; + } + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + if (!extensions.streamConsumerGLTexture) + { + return EglBadAttribute() << "Consumer GL extension not enabled"; + } + // Again not in spec but it should be positive anyways + if (value < 0) + { + return EglBadParameter() << "Timeout must be positive"; + } + break; + default: + return EglBadAttribute() << "Invalid stream attribute"; + } + return NoError(); } -namespace egl +Error ValidateCreateImageKHRMipLevelCommon(gl::Context *context, + const gl::Texture *texture, + EGLAttrib level) { + // Note that the spec EGL_KHR_create_image spec does not explicitly specify an error + // when the level is outside the base/max level range, but it does mention that the + // level "must be a part of the complete texture object <buffer>". It can be argued + // that out-of-range levels are not a part of the complete texture. + const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel(); + if (level > 0 && + (!texture->isMipmapComplete() || static_cast<GLuint>(level) < effectiveBaseLevel || + static_cast<GLuint>(level) > texture->getTextureState().getMipmapMaxLevel())) + { + return EglBadParameter() << "texture must be complete if level is non-zero."; + } + + if (level == 0 && !texture->isMipmapComplete() && + TextureHasNonZeroMipLevelsSpecified(context, texture)) + { + return EglBadParameter() << "if level is zero and the texture is incomplete, it must " + "have no mip levels specified except zero."; + } + + return NoError(); +} + +Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute) +{ + switch (attribute) + { + case EGL_BUFFER_SIZE: + case EGL_ALPHA_SIZE: + case EGL_BLUE_SIZE: + case EGL_GREEN_SIZE: + case EGL_RED_SIZE: + case EGL_DEPTH_SIZE: + case EGL_STENCIL_SIZE: + case EGL_CONFIG_CAVEAT: + case EGL_CONFIG_ID: + case EGL_LEVEL: + case EGL_NATIVE_RENDERABLE: + case EGL_NATIVE_VISUAL_ID: + case EGL_NATIVE_VISUAL_TYPE: + case EGL_SAMPLES: + case EGL_SAMPLE_BUFFERS: + case EGL_SURFACE_TYPE: + case EGL_TRANSPARENT_TYPE: + case EGL_TRANSPARENT_BLUE_VALUE: + case EGL_TRANSPARENT_GREEN_VALUE: + case EGL_TRANSPARENT_RED_VALUE: + case EGL_BIND_TO_TEXTURE_RGB: + case EGL_BIND_TO_TEXTURE_RGBA: + case EGL_MIN_SWAP_INTERVAL: + case EGL_MAX_SWAP_INTERVAL: + case EGL_LUMINANCE_SIZE: + case EGL_ALPHA_MASK_SIZE: + case EGL_COLOR_BUFFER_TYPE: + case EGL_RENDERABLE_TYPE: + case EGL_MATCH_NATIVE_PIXMAP: + case EGL_CONFORMANT: + case EGL_MAX_PBUFFER_WIDTH: + case EGL_MAX_PBUFFER_HEIGHT: + case EGL_MAX_PBUFFER_PIXELS: + break; + + case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: + if (!display->getExtensions().surfaceOrientation) + { + return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled."; + } + break; + + case EGL_COLOR_COMPONENT_TYPE_EXT: + if (!display->getExtensions().pixelFormatFloat) + { + return EglBadAttribute() << "EGL_EXT_pixel_format_float is not enabled."; + } + break; + + default: + return EglBadAttribute() << "Unknown attribute."; + } + + return NoError(); +} + +Error ValidateConfigAttributes(const Display *display, const AttributeMap &attributes) +{ + for (const auto &attrib : attributes) + { + ANGLE_TRY(ValidateConfigAttribute(display, attrib.first)); + } + + return NoError(); +} + +Error ValidatePlatformType(const ClientExtensions &clientExtensions, EGLAttrib platformType) +{ + switch (platformType) + { + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + break; + + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + if (!clientExtensions.platformANGLED3D) + { + return EglBadAttribute() << "Direct3D platform is unsupported."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: + if (!clientExtensions.platformANGLEOpenGL) + { + return EglBadAttribute() << "OpenGL platform is unsupported."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE: + if (!clientExtensions.platformANGLENULL) + { + return EglBadAttribute() << "Display type EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE " + "requires EGL_ANGLE_platform_angle_null."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE: + if (!clientExtensions.platformANGLEVulkan) + { + return EglBadAttribute() << "Vulkan platform is unsupported."; + } + break; + + default: + return EglBadAttribute() << "Unknown platform type."; + } + + return NoError(); +} + +Error ValidateGetPlatformDisplayCommon(EGLenum platform, + void *native_display, + const AttributeMap &attribMap) +{ + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); + + switch (platform) + { + case EGL_PLATFORM_ANGLE_ANGLE: + if (!clientExtensions.platformANGLE) + { + return EglBadParameter() << "Platform ANGLE extension is not active"; + } + break; + case EGL_PLATFORM_DEVICE_EXT: + if (!clientExtensions.platformDevice) + { + return EglBadParameter() << "Platform Device extension is not active"; + } + break; + default: + return EglBadConfig() << "Bad platform type."; + } + + if (platform == EGL_PLATFORM_ANGLE_ANGLE) + { + EGLAttrib platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; + EGLAttrib deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; + bool enableAutoTrimSpecified = false; + bool deviceTypeSpecified = false; + bool presentPathSpecified = false; + + Optional<EGLAttrib> majorVersion; + Optional<EGLAttrib> minorVersion; + + for (const auto &curAttrib : attribMap) + { + const EGLAttrib value = curAttrib.second; + + switch (curAttrib.first) + { + case EGL_PLATFORM_ANGLE_TYPE_ANGLE: + { + ANGLE_TRY(ValidatePlatformType(clientExtensions, value)); + platformType = value; + break; + } + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE: + if (value != EGL_DONT_CARE) + { + majorVersion = value; + } + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE: + if (value != EGL_DONT_CARE) + { + minorVersion = value; + } + break; + + case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE: + switch (value) + { + case EGL_TRUE: + case EGL_FALSE: + break; + default: + return EglBadAttribute() << "Invalid automatic trim attribute"; + } + enableAutoTrimSpecified = true; + break; + + case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE: + if (!clientExtensions.experimentalPresentPath) + { + return EglBadAttribute() + << "EGL_ANGLE_experimental_present_path extension not active"; + } + + switch (value) + { + case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: + case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE: + break; + default: + return EglBadAttribute() + << "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE"; + } + presentPathSpecified = true; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE: + switch (value) + { + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + deviceTypeSpecified = true; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + // This is a hidden option, accepted by the OpenGL back-end. + break; + + default: + return EglBadAttribute() << "Invalid value for " + "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE " + "attrib"; + } + deviceType = value; + break; + + case EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE: + if (!clientExtensions.platformANGLE) + { + return EglBadAttribute() << "EGL_ANGLE_platform_angle extension not active"; + } + if (value != EGL_TRUE && value != EGL_FALSE && value != EGL_DONT_CARE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE " + "must be EGL_TRUE, EGL_FALSE, or " + "EGL_DONT_CARE."; + } + break; + + default: + break; + } + } + + if (!majorVersion.valid() && minorVersion.valid()) + { + return EglBadAttribute() + << "Must specify major version if you specify a minor version."; + } + + if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE " + "requires a device type of " + "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or " + "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE."; + } + + if (platformType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) + { + if ((majorVersion.valid() && majorVersion.value() != 1) || + (minorVersion.valid() && minorVersion.value() != 0)) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE currently " + "only supports Vulkan 1.0."; + } + } + } + else if (platform == EGL_PLATFORM_DEVICE_EXT) + { + Device *eglDevice = reinterpret_cast<Device *>(native_display); + if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice)) + { + return EglBadAttribute() << "native_display should be a valid EGL device if " + "platform equals EGL_PLATFORM_DEVICE_EXT"; + } + } + else + { + UNREACHABLE(); + } + + return NoError(); +} + +} // namespace Error ValidateDisplay(const Display *display) { if (display == EGL_NO_DISPLAY) { - return Error(EGL_BAD_DISPLAY, "display is EGL_NO_DISPLAY."); + return EglBadDisplay() << "display is EGL_NO_DISPLAY."; } if (!Display::isValidDisplay(display)) { - return Error(EGL_BAD_DISPLAY, "display is not a valid display."); + return EglBadDisplay() << "display is not a valid display."; } if (!display->isInitialized()) { - return Error(EGL_NOT_INITIALIZED, "display is not initialized."); + return EglNotInitialized() << "display is not initialized."; + } + + if (display->isDeviceLost()) + { + return EglContextLost() << "display had a context loss"; } - return Error(EGL_SUCCESS); + return NoError(); } -Error ValidateSurface(const Display *display, Surface *surface) +Error ValidateSurface(const Display *display, const Surface *surface) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidSurface(surface)) { - return Error(EGL_BAD_SURFACE); + return EglBadSurface(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateConfig(const Display *display, const Config *config) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidConfig(config)) { - return Error(EGL_BAD_CONFIG); + return EglBadConfig(); } - return Error(EGL_SUCCESS); + return NoError(); } -Error ValidateContext(const Display *display, gl::Context *context) +Error ValidateContext(const Display *display, const gl::Context *context) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidContext(context)) { - return Error(EGL_BAD_CONTEXT); + return EglBadContext(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateImage(const Display *display, const Image *image) { - Error error = ValidateDisplay(display); - if (error.isError()) + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->isValidImage(image)) { - return error; + return EglBadParameter() << "image is not valid."; } - if (!display->isValidImage(image)) + return NoError(); +} + +Error ValidateStream(const Display *display, const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.stream) + { + return EglBadAccess() << "Stream extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { - return Error(EGL_BAD_PARAMETER, "image is not valid."); + return EglBadStream() << "Invalid stream"; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, const AttributeMap& attributes) { - Error error = ValidateConfig(display, configuration); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, configuration)); // Get the requested client version (default is 1) and check it is 2 or 3. - EGLint clientMajorVersion = 1; - EGLint clientMinorVersion = 0; - EGLint contextFlags = 0; + EGLAttrib clientMajorVersion = 1; + EGLAttrib clientMinorVersion = 0; + EGLAttrib contextFlags = 0; bool resetNotification = false; - bool robustAccess = false; for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -215,28 +591,27 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: // Only valid for OpenGL (non-ES) contexts - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: if (!display->getExtensions().createContextRobustness) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value != EGL_TRUE && value != EGL_FALSE) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } - robustAccess = (value == EGL_TRUE); break; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: - static_assert(EGL_LOSE_CONTEXT_ON_RESET_EXT == EGL_LOSE_CONTEXT_ON_RESET_KHR, "EGL extension enums not equal."); - static_assert(EGL_NO_RESET_NOTIFICATION_EXT == EGL_NO_RESET_NOTIFICATION_KHR, "EGL extension enums not equal."); - // same as EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, fall through + return EglBadAttribute() << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR is not" + << " valid for GLES with EGL 1.4 and KHR_create_context. Use" + << " EXT_create_context_robustness."; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: if (!display->getExtensions().createContextRobustness) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT) { @@ -244,34 +619,143 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context } else if (value != EGL_NO_RESET_NOTIFICATION_EXT) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_CONTEXT_OPENGL_NO_ERROR_KHR: if (!display->getExtensions().createContextNoError) { - return Error(EGL_BAD_ATTRIBUTE, "Invalid Context attribute."); + return EglBadAttribute() << "Invalid Context attribute."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "Attribute must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE: + if (!display->getExtensions().createContextWebGLCompatibility) + { + return EglBadAttribute() << "Attribute " + "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires " + "EGL_ANGLE_create_context_webgl_compatibility."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() + << "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM: + if (!display->getExtensions().createContextBindGeneratesResource) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM requires " + "EGL_CHROMIUM_create_context_bind_generates_resource."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM " + "must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE: + if (!display->getExtensions().displayTextureShareGroup) + { + return EglBadAttribute() << "Attribute " + "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE requires " + "EGL_ANGLE_display_texture_share_group."; } if (value != EGL_TRUE && value != EGL_FALSE) { - return Error(EGL_BAD_ATTRIBUTE, "Attribute must be EGL_TRUE or EGL_FALSE."); + return EglBadAttribute() + << "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE must be EGL_TRUE or EGL_FALSE."; + } + if (shareContext && + (shareContext->usingDisplayTextureShareGroup() != (value == EGL_TRUE))) + { + return EglBadAttribute() << "All contexts within a share group must be " + "created with the same value of " + "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE."; + } + break; + + case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE: + if (!display->getExtensions().createContextClientArrays) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE requires " + "EGL_ANGLE_create_context_client_arrays."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE must " + "be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE: + if (!display->getExtensions().programCacheControl) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE " + "requires EGL_ANGLE_program_cache_control."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE must " + "be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute() << "Unknown attribute."; } } - if ((clientMajorVersion != 2 && clientMajorVersion != 3) || clientMinorVersion != 0) - { - return Error(EGL_BAD_CONFIG); - } - - if (clientMajorVersion == 3 && !(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR) && !(configuration->configCaveat & EGL_NON_CONFORMANT_CONFIG)) + switch (clientMajorVersion) { - return Error(EGL_BAD_CONFIG); + case 2: + if (clientMinorVersion != 0) + { + return EglBadConfig(); + } + break; + case 3: + if (clientMinorVersion != 0 && clientMinorVersion != 1) + { + return EglBadConfig(); + } + if (!(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR)) + { + return EglBadConfig(); + } + if (display->getMaxSupportedESVersion() < + gl::Version(static_cast<GLuint>(clientMajorVersion), + static_cast<GLuint>(clientMinorVersion))) + { + return EglBadConfig() << "Requested GLES version is not supported."; + } + break; + default: + return EglBadConfig(); + break; } // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES @@ -279,18 +763,7 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR); if ((contextFlags & ~validContextFlags) != 0) { - return Error(EGL_BAD_ATTRIBUTE); - } - - if ((contextFlags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) > 0) - { - robustAccess = true; - } - - if (robustAccess) - { - // Unimplemented - return Error(EGL_BAD_CONFIG); + return EglBadAttribute(); } if (shareContext) @@ -298,43 +771,40 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context // Shared context is invalid or is owned by another display if (!display->isValidContext(shareContext)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if (shareContext->isResetNotificationEnabled() != resetNotification) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } - if (shareContext->getClientVersion() != clientMajorVersion) + if (shareContext->getClientMajorVersion() != clientMajorVersion || + shareContext->getClientMinorVersion() != clientMinorVersion) { - return Error(EGL_BAD_CONTEXT); + return EglBadContext(); } } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); if (!display->isValidNativeWindow(window)) { - return Error(EGL_BAD_NATIVE_WINDOW); + return EglBadNativeWindow(); } const DisplayExtensions &displayExtensions = display->getExtensions(); for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -344,23 +814,23 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin case EGL_BACK_BUFFER: break; case EGL_SINGLE_BUFFER: - return Error(EGL_BAD_MATCH); // Rendering directly to front buffer not supported + return EglBadMatch(); // Rendering directly to front buffer not supported default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: if (!displayExtensions.postSubBuffer) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -368,68 +838,77 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin case EGL_HEIGHT: if (!displayExtensions.windowFixedSize) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; case EGL_FIXED_SIZE_ANGLE: if (!displayExtensions.windowFixedSize) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_SURFACE_ORIENTATION_ANGLE: if (!displayExtensions.surfaceOrientation) { - return Error(EGL_BAD_ATTRIBUTE, "EGL_ANGLE_surface_orientation is not enabled."); + return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled."; } break; case EGL_VG_COLORSPACE: - return Error(EGL_BAD_MATCH); + return EglBadMatch(); case EGL_VG_ALPHA_FORMAT: - return Error(EGL_BAD_MATCH); + return EglBadMatch(); case EGL_DIRECT_COMPOSITION_ANGLE: if (!displayExtensions.directComposition) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (Display::hasExistingWindowSurface(window)) { - return Error(EGL_BAD_ALLOC); + return EglBadAlloc(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -437,7 +916,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_HEIGHT: if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; @@ -452,7 +931,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_TEXTURE_RGBA: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -463,7 +942,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_TEXTURE_2D: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -479,60 +958,66 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error( - EGL_BAD_ATTRIBUTE, - "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without " - "EGL_ANGLE_flexible_surface_compatibility support."); + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used " + "without EGL_ANGLE_flexible_surface_compatibility support."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check const Caps &caps = display->getCaps(); - EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); - EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } - EGLint width = attributes.get(EGL_WIDTH, 0); - EGLint height = attributes.get(EGL_HEIGHT, 0); + EGLint width = static_cast<EGLint>(attributes.get(EGL_WIDTH, 0)); + EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, 0)); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#endif - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); @@ -541,22 +1026,33 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: if (!displayExtensions.d3dShareHandleClientBuffer) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } if (buffer == nullptr) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; + case EGL_D3D_TEXTURE_ANGLE: + if (!displayExtensions.d3dTextureClientBuffer) + { + return EglBadParameter(); + } + if (buffer == nullptr) + { + return EglBadParameter(); + } + break; + default: - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -564,11 +1060,11 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_HEIGHT: if (!displayExtensions.d3dShareHandleClientBuffer) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; @@ -580,7 +1076,7 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_TEXTURE_RGBA: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -591,7 +1087,7 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_TEXTURE_2D: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -601,58 +1097,143 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error( - EGL_BAD_ATTRIBUTE, - "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used without " - "EGL_ANGLE_flexible_surface_compatibility support."); + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used " + "without EGL_ANGLE_flexible_surface_compatibility support."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } - EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); - EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) { - EGLint width = attributes.get(EGL_WIDTH, 0); - EGLint height = attributes.get(EGL_HEIGHT, 0); + EGLint width = static_cast<EGLint>(attributes.get(EGL_WIDTH, 0)); + EGLint height = static_cast<EGLint>(attributes.get(EGL_HEIGHT, 0)); if (width == 0 || height == 0) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } -// On Windows Store, we know the originating texture came from D3D11, so bypass this check -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) const Caps &caps = display->getCaps(); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); + } + } + + ANGLE_TRY(display->validateClientBuffer(config, buftype, buffer, attributes)); + + return NoError(); +} + +Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context) +{ + if (context == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) + { + return EglBadMatch() << "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE"; + } + + // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH + // error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE. + if (context != EGL_NO_CONTEXT && (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE)) + { + if (display->getExtensions().surfacelessContext) + { + if ((draw == EGL_NO_SURFACE) != (read == EGL_NO_SURFACE)) + { + return EglBadMatch() << "If ctx is not EGL_NOT_CONTEXT, draw or read must " + "both be EGL_NO_SURFACE, or both not"; + } + } + else + { + return EglBadMatch() + << "If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE"; } -#endif } - return Error(EGL_SUCCESS); + // If either of draw or read is a valid surface and the other is EGL_NO_SURFACE, an + // EGL_BAD_MATCH error is generated. + if ((read == EGL_NO_SURFACE) != (draw == EGL_NO_SURFACE)) + { + return EglBadMatch() + << "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE"; + } + + if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) + { + return EglBadDisplay() << "'dpy' not a valid EGLDisplay handle"; + } + + // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null + if (!display->isInitialized() && + (context != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) + { + return EglNotInitialized() << "'dpy' not initialized"; + } + + if (context != EGL_NO_CONTEXT) + { + ANGLE_TRY(ValidateContext(display, context)); + } + + if (display->isInitialized() && display->testDeviceLost()) + { + return EglContextLost(); + } + + Surface *drawSurface = static_cast<Surface *>(draw); + if (draw != EGL_NO_SURFACE) + { + ANGLE_TRY(ValidateSurface(display, drawSurface)); + } + + Surface *readSurface = static_cast<Surface *>(read); + if (read != EGL_NO_SURFACE) + { + ANGLE_TRY(ValidateSurface(display, readSurface)); + } + + if (readSurface) + { + ANGLE_TRY(ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface, + context->getConfig(), readSurface->getType())); + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + + if (drawSurface) + { + ANGLE_TRY(ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface, + context->getConfig(), drawSurface->getType())); + } + } + return NoError(); } Error ValidateCompatibleConfigs(const Display *display, @@ -669,7 +1250,7 @@ Error ValidateCompatibleConfigs(const Display *display, bool colorBufferCompat = config1->colorBufferType == config2->colorBufferType; if (!colorBufferCompat) { - return Error(EGL_BAD_MATCH, "Color buffer types are not compatible."); + return EglBadMatch() << "Color buffer types are not compatible."; } bool colorCompat = @@ -678,24 +1259,30 @@ Error ValidateCompatibleConfigs(const Display *display, config1->luminanceSize == config2->luminanceSize; if (!colorCompat) { - return Error(EGL_BAD_MATCH, "Color buffer sizes are not compatible."); + return EglBadMatch() << "Color buffer sizes are not compatible."; + } + + bool componentTypeCompat = config1->colorComponentType == config2->colorComponentType; + if (!componentTypeCompat) + { + return EglBadMatch() << "Color buffer component types are not compatible."; } bool dsCompat = config1->depthSize == config2->depthSize && config1->stencilSize == config2->stencilSize; if (!dsCompat) { - return Error(EGL_BAD_MATCH, "Depth-stencil buffer types are not compatible."); + return EglBadMatch() << "Depth-stencil buffer types are not compatible."; } } bool surfaceTypeCompat = (config1->surfaceType & config2->surfaceType & surfaceType) != 0; if (!surfaceTypeCompat) { - return Error(EGL_BAD_MATCH, "Surface types are not compatible."); + return EglBadMatch() << "Surface types are not compatible."; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateImageKHR(const Display *display, @@ -704,11 +1291,7 @@ Error ValidateCreateImageKHR(const Display *display, EGLClientBuffer buffer, const AttributeMap &attributes) { - Error error = ValidateContext(display, context); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateContext(display, context)); const DisplayExtensions &displayExtensions = display->getExtensions(); @@ -717,7 +1300,7 @@ Error ValidateCreateImageKHR(const Display *display, // It is out of spec what happens when calling an extension function when the extension is // not available. // EGL_BAD_DISPLAY seems like a reasonable error. - return Error(EGL_BAD_DISPLAY, "EGL_KHR_image not supported."); + return EglBadDisplay() << "EGL_KHR_image not supported."; } // TODO(geofflang): Complete validation from EGL_KHR_image_base: @@ -727,8 +1310,8 @@ Error ValidateCreateImageKHR(const Display *display, for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -740,8 +1323,8 @@ Error ValidateCreateImageKHR(const Display *display, break; default: - return Error(EGL_BAD_PARAMETER, - "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."); + return EglBadParameter() + << "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."; } break; @@ -749,28 +1332,27 @@ Error ValidateCreateImageKHR(const Display *display, if (!displayExtensions.glTexture2DImage && !displayExtensions.glTextureCubemapImage && !displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, - "EGL_GL_TEXTURE_LEVEL_KHR cannot be used without " - "KHR_gl_texture_*_image support."); + return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be used " + "without KHR_gl_texture_*_image support."; } if (value < 0) { - return Error(EGL_BAD_PARAMETER, "EGL_GL_TEXTURE_LEVEL_KHR cannot be negative."); + return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be negative."; } break; case EGL_GL_TEXTURE_ZOFFSET_KHR: if (!displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, - "EGL_GL_TEXTURE_ZOFFSET_KHR cannot be used without " - "KHR_gl_texture_3D_image support."); + return EglBadParameter() << "EGL_GL_TEXTURE_ZOFFSET_KHR cannot be used " + "without KHR_gl_texture_3D_image support."; } break; default: - return Error(EGL_BAD_PARAMETER, "invalid attribute: 0x%X", attribute); + return EglBadParameter() + << "invalid attribute: 0x" << std::hex << std::uppercase << attribute; } } @@ -780,48 +1362,35 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTexture2DImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_2D_image not supported."); + return EglBadParameter() << "KHR_gl_texture_2D_image not supported."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a 2D texture with the name 0."); + return EglBadParameter() << "buffer cannot reference a 2D texture with the name 0."; } const gl::Texture *texture = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (texture == nullptr || texture->getTarget() != GL_TEXTURE_2D) { - return Error(EGL_BAD_PARAMETER, "target is not a 2D texture."); + return EglBadParameter() << "target is not a 2D texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); if (texture->getWidth(GL_TEXTURE_2D, static_cast<size_t>(level)) == 0 || texture->getHeight(GL_TEXTURE_2D, static_cast<size_t>(level)) == 0) { - return Error(EGL_BAD_PARAMETER, - "target 2D texture does not have a valid size at specified level."); - } - - if (level > 0 && (!texture->isMipmapComplete() || - static_cast<size_t>(level) >= texture->getMipCompleteLevels())) - { - return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); + return EglBadParameter() + << "target 2D texture does not have a valid size at specified level."; } - if (level == 0 && !texture->isMipmapComplete() && - TextureHasNonZeroMipLevelsSpecified(context, texture)) - { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have no mip " - "levels specified except zero."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); } break; @@ -834,57 +1403,44 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTextureCubemapImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_cubemap_image not supported."); + return EglBadParameter() << "KHR_gl_texture_cubemap_image not supported."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a cubemap texture with the name 0."); + return EglBadParameter() + << "buffer cannot reference a cubemap texture with the name 0."; } const gl::Texture *texture = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (texture == nullptr || texture->getTarget() != GL_TEXTURE_CUBE_MAP) { - return Error(EGL_BAD_PARAMETER, "target is not a cubemap texture."); + return EglBadParameter() << "target is not a cubemap texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); GLenum cubeMapFace = egl_gl::EGLCubeMapTargetToGLCubeMapTarget(target); if (texture->getWidth(cubeMapFace, static_cast<size_t>(level)) == 0 || texture->getHeight(cubeMapFace, static_cast<size_t>(level)) == 0) { - return Error(EGL_BAD_PARAMETER, - "target cubemap texture does not have a valid size at specified level " - "and face."); - } - - if (level > 0 && (!texture->isMipmapComplete() || - static_cast<size_t>(level) >= texture->getMipCompleteLevels())) - { - return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); + return EglBadParameter() << "target cubemap texture does not have a valid " + "size at specified level and face."; } - if (level == 0 && !texture->isMipmapComplete() && - TextureHasNonZeroMipLevelsSpecified(context, texture)) - { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have no mip " - "levels specified except zero."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); if (level == 0 && !texture->isMipmapComplete() && CubeTextureHasUnspecifiedLevel0Face(texture)) { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have all of " - "its faces specified at level zero."); + return EglBadParameter() << "if level is zero and the texture is incomplete, " + "it must have all of its faces specified at level " + "zero."; } } break; @@ -893,58 +1449,45 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_3D_image not supported."); + return EglBadParameter() << "KHR_gl_texture_3D_image not supported."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a 3D texture with the name 0."); + return EglBadParameter() << "buffer cannot reference a 3D texture with the name 0."; } const gl::Texture *texture = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (texture == nullptr || texture->getTarget() != GL_TEXTURE_3D) { - return Error(EGL_BAD_PARAMETER, "target is not a 3D texture."); + return EglBadParameter() << "target is not a 3D texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); - EGLint zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib zOffset = attributes.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0); if (texture->getWidth(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0 || texture->getHeight(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0 || texture->getDepth(GL_TEXTURE_3D, static_cast<size_t>(level)) == 0) { - return Error(EGL_BAD_PARAMETER, - "target 3D texture does not have a valid size at specified level."); + return EglBadParameter() + << "target 3D texture does not have a valid size at specified level."; } if (static_cast<size_t>(zOffset) >= texture->getDepth(GL_TEXTURE_3D, static_cast<size_t>(level))) { - return Error(EGL_BAD_PARAMETER, - "target 3D texture does not have enough layers for the specified Z " - "offset at the specified level."); - } - - if (level > 0 && (!texture->isMipmapComplete() || - static_cast<size_t>(level) >= texture->getMipCompleteLevels())) - { - return Error(EGL_BAD_PARAMETER, "texture must be complete if level is non-zero."); + return EglBadParameter() << "target 3D texture does not have enough layers " + "for the specified Z offset at the specified " + "level."; } - if (level == 0 && !texture->isMipmapComplete() && - TextureHasNonZeroMipLevelsSpecified(context, texture)) - { - return Error(EGL_BAD_PARAMETER, - "if level is zero and the texture is incomplete, it must have no mip " - "levels specified except zero."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); } break; @@ -952,75 +1495,71 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glRenderbufferImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_renderbuffer_image not supported."); + return EglBadParameter() << "KHR_gl_renderbuffer_image not supported."; } if (attributes.contains(EGL_GL_TEXTURE_LEVEL_KHR)) { - return Error(EGL_BAD_PARAMETER, - "EGL_GL_TEXTURE_LEVEL_KHR cannot be used in conjunction with a " - "renderbuffer target."); + return EglBadParameter() << "EGL_GL_TEXTURE_LEVEL_KHR cannot be used in " + "conjunction with a renderbuffer target."; } if (buffer == 0) { - return Error(EGL_BAD_PARAMETER, - "buffer cannot reference a renderbuffer with the name 0."); + return EglBadParameter() + << "buffer cannot reference a renderbuffer with the name 0."; } const gl::Renderbuffer *renderbuffer = context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer)); if (renderbuffer == nullptr) { - return Error(EGL_BAD_PARAMETER, "target is not a renderbuffer."); + return EglBadParameter() << "target is not a renderbuffer."; } if (renderbuffer->getSamples() > 0) { - return Error(EGL_BAD_PARAMETER, "target renderbuffer cannot be multisampled."); + return EglBadParameter() << "target renderbuffer cannot be multisampled."; } } break; default: - return Error(EGL_BAD_PARAMETER, "invalid target: 0x%X", target); + return EglBadParameter() + << "invalid target: 0x" << std::hex << std::uppercase << target; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateDestroyImageKHR(const Display *display, const Image *image) { - Error error = ValidateImage(display, image); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateImage(display, image)); if (!display->getExtensions().imageBase && !display->getExtensions().image) { // It is out of spec what happens when calling an extension function when the extension is // not available. // EGL_BAD_DISPLAY seems like a reasonable error. - return Error(EGL_BAD_DISPLAY); + return EglBadDisplay(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list) { - const ClientExtensions &clientExtensions = Display::getClientExtensions(); + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); if (!clientExtensions.deviceCreation) { - return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + return EglBadAccess() << "Device creation extension not active"; } if (attrib_list != nullptr && attrib_list[0] != EGL_NONE) { - return Error(EGL_BAD_ATTRIBUTE, "Invalid attrib_list parameter"); + return EglBadAttribute() << "Invalid attrib_list parameter"; } switch (device_type) @@ -1028,35 +1567,935 @@ Error ValidateCreateDeviceANGLE(EGLint device_type, case EGL_D3D11_DEVICE_ANGLE: if (!clientExtensions.deviceCreationD3D11) { - return Error(EGL_BAD_ATTRIBUTE, "D3D11 device creation extension not active"); + return EglBadAttribute() << "D3D11 device creation extension not active"; } break; default: - return Error(EGL_BAD_ATTRIBUTE, "Invalid device_type parameter"); + return EglBadAttribute() << "Invalid device_type parameter"; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateReleaseDeviceANGLE(Device *device) { - const ClientExtensions &clientExtensions = Display::getClientExtensions(); + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); if (!clientExtensions.deviceCreation) { - return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + return EglBadAccess() << "Device creation extension not active"; } if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device)) { - return Error(EGL_BAD_DEVICE_EXT, "Invalid device parameter"); + return EglBadDevice() << "Invalid device parameter"; } Display *owningDisplay = device->getOwningDisplay(); if (owningDisplay != nullptr) { - return Error(EGL_BAD_DEVICE_EXT, "Device must have been created using eglCreateDevice"); + return EglBadDevice() << "Device must have been created using eglCreateDevice"; + } + + return NoError(); +} + +Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.stream) + { + return EglBadAlloc() << "Stream extension not active"; + } + + for (const auto &attributeIter : attributes) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + ANGLE_TRY(ValidateStreamAttribute(attribute, value, displayExtensions)); + } + + return NoError(); +} + +Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream) +{ + ANGLE_TRY(ValidateStream(display, stream)); + return NoError(); +} + +Error ValidateStreamAttribKHR(const Display *display, + const Stream *stream, + EGLint attribute, + EGLint value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR) + { + return EglBadState() << "Bad stream state"; + } + + return ValidateStreamAttribute(attribute, value, display->getExtensions()); +} + +Error ValidateQueryStreamKHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + case EGL_CONSUMER_LATENCY_USEC_KHR: + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + if (!display->getExtensions().streamConsumerGLTexture) + { + return EglBadAttribute() << "Consumer GLTexture extension not active"; + } + break; + default: + return EglBadAttribute() << "Invalid attribute"; } - return Error(EGL_SUCCESS); + return NoError(); } + +Error ValidateQueryStreamu64KHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLuint64KHR *value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + switch (attribute) + { + case EGL_CONSUMER_FRAME_KHR: + case EGL_PRODUCER_FRAME_KHR: + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + + return NoError(); } + +Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateContext(display, context)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (!context->getExtensions().eglStreamConsumerExternal) + { + return EglBadAccess() << "EGL stream consumer external GL extension not enabled"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + // Lookup the texture and ensure it is correct + gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() << "No external texture bound"; + } + + return NoError(); +} + +Error ValidateStreamConsumerAcquireKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (!stream->isConsumerBoundToContext(context)) + { + return EglBadAccess() << "Current GL context not associated with stream consumer"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && + stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) + { + return EglBadAccess() << "Invalid stream consumer type"; + } + + // Note: technically EGL_STREAM_STATE_EMPTY_KHR is a valid state when the timeout is non-zero. + // However, the timeout is effectively ignored since it has no useful functionality with the + // current producers that are implemented, so we don't allow that state + if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + return NoError(); +} + +Error ValidateStreamConsumerReleaseKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (!stream->isConsumerBoundToContext(context)) + { + return EglBadAccess() << "Current GL context not associated with stream consumer"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && + stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) + { + return EglBadAccess() << "Invalid stream consumer type"; + } + + if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + return NoError(); +} + +Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display, + gl::Context *context, + const Stream *stream, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + // Although technically not a requirement in spec, the context needs to be checked for support + // for external textures or future logic will cause assertations. This extension is also + // effectively useless without external textures. + if (!context->getExtensions().eglStreamConsumerExternal) + { + return EglBadAccess() << "EGL stream consumer external GL extension not enabled"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + const gl::Caps &glCaps = context->getCaps(); + + EGLAttrib colorBufferType = EGL_RGB_BUFFER; + EGLAttrib planeCount = -1; + EGLAttrib plane[3]; + for (int i = 0; i < 3; i++) + { + plane[i] = -1; + } + for (const auto &attributeIter : attribs) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + switch (attribute) + { + case EGL_COLOR_BUFFER_TYPE: + if (value != EGL_RGB_BUFFER && value != EGL_YUV_BUFFER_EXT) + { + return EglBadParameter() << "Invalid color buffer type"; + } + colorBufferType = value; + break; + case EGL_YUV_NUMBER_OF_PLANES_EXT: + // planeCount = -1 is a tag for the default plane count so the value must be checked + // to be positive here to ensure future logic doesn't break on invalid negative + // inputs + if (value < 0) + { + return EglBadMatch() << "Invalid plane count"; + } + planeCount = value; + break; + default: + if (attribute >= EGL_YUV_PLANE0_TEXTURE_UNIT_NV && + attribute <= EGL_YUV_PLANE2_TEXTURE_UNIT_NV) + { + if ((value < 0 || + value >= static_cast<EGLAttrib>(glCaps.maxCombinedTextureImageUnits)) && + value != EGL_NONE) + { + return EglBadAccess() << "Invalid texture unit"; + } + plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value; + } + else + { + return EglBadAttribute() << "Invalid attribute"; + } + } + } + + if (colorBufferType == EGL_RGB_BUFFER) + { + if (planeCount > 0) + { + return EglBadMatch() << "Plane count must be 0 for RGB buffer"; + } + for (int i = 0; i < 3; i++) + { + if (plane[i] != -1) + { + return EglBadMatch() << "Planes cannot be specified"; + } + } + + // Lookup the texture and ensure it is correct + gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() << "No external texture bound"; + } + } + else + { + if (planeCount == -1) + { + planeCount = 2; + } + if (planeCount < 1 || planeCount > 3) + { + return EglBadMatch() << "Invalid YUV plane count"; + } + for (EGLAttrib i = planeCount; i < 3; i++) + { + if (plane[i] != -1) + { + return EglBadMatch() << "Invalid plane specified"; + } + } + + // Set to ensure no texture is referenced more than once + std::set<gl::Texture *> textureSet; + for (EGLAttrib i = 0; i < planeCount; i++) + { + if (plane[i] == -1) + { + return EglBadMatch() << "Not all planes specified"; + } + if (plane[i] != EGL_NONE) + { + gl::Texture *texture = context->getGLState().getSamplerTexture( + static_cast<unsigned int>(plane[i]), GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() + << "No external texture bound at one or more specified texture units"; + } + if (textureSet.find(texture) != textureSet.end()) + { + return EglBadAccess() << "Multiple planes bound to same texture object"; + } + textureSet.insert(texture); + } + } + } + + return NoError(); +} + +Error ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamProducerD3DTextureNV12) + { + return EglBadAccess() << "Stream producer extension not active"; + } + + ANGLE_TRY(ValidateStream(display, stream)); + + if (!attribs.isEmpty()) + { + return EglBadAttribute() << "Invalid attribute"; + } + + if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR) + { + return EglBadState() << "Stream not in connecting state"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV || + stream->getPlaneCount() != 2) + { + return EglBadMatch() << "Incompatible stream consumer type"; + } + + return NoError(); +} + +Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + void *texture, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamProducerD3DTextureNV12) + { + return EglBadAccess() << "Stream producer extension not active"; + } + + ANGLE_TRY(ValidateStream(display, stream)); + + for (auto &attributeIter : attribs) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + switch (attribute) + { + case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE: + if (value < 0) + { + return EglBadParameter() << "Invalid subresource index"; + } + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + } + + if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR && + stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Stream not fully configured"; + } + + if (stream->getProducerType() != Stream::ProducerType::D3D11TextureNV12) + { + return EglBadMatch() << "Incompatible stream producer"; + } + + if (texture == nullptr) + { + return EglBadParameter() << "Texture is null"; + } + + return stream->validateD3D11NV12Texture(texture); +} + +Error ValidateGetSyncValuesCHROMIUM(const Display *display, + const Surface *surface, + const EGLuint64KHR *ust, + const EGLuint64KHR *msc, + const EGLuint64KHR *sbc) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.getSyncValues) + { + return EglBadAccess() << "getSyncValues extension not active"; + } + + if (display->isDeviceLost()) + { + return EglContextLost() << "Context is lost."; + } + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "getSyncValues surface cannot be EGL_NO_SURFACE"; + } + + if (!surface->directComposition()) + { + return EglBadSurface() << "getSyncValues surface requires Direct Composition to be enabled"; + } + + if (ust == nullptr) + { + return EglBadParameter() << "ust is null"; + } + + if (msc == nullptr) + { + return EglBadParameter() << "msc is null"; + } + + if (sbc == nullptr) + { + return EglBadParameter() << "sbc is null"; + } + + return NoError(); +} + +Error ValidateSwapBuffersWithDamageEXT(const Display *display, + const Surface *surface, + EGLint *rects, + EGLint n_rects) +{ + Error error = ValidateSurface(display, surface); + if (error.isError()) + { + return error; + } + + if (!display->getExtensions().swapBuffersWithDamage) + { + // It is out of spec what happens when calling an extension function when the extension is + // not available. EGL_BAD_DISPLAY seems like a reasonable error. + return EglBadDisplay() << "EGL_EXT_swap_buffers_with_damage is not available."; + } + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Swap surface cannot be EGL_NO_SURFACE."; + } + + if (n_rects < 0) + { + return EglBadParameter() << "n_rects cannot be negative."; + } + + if (n_rects > 0 && rects == nullptr) + { + return EglBadParameter() << "n_rects cannot be greater than zero when rects is NULL."; + } + + // TODO(jmadill): Validate Surface is bound to the thread. + + return NoError(); +} + +Error ValidateGetConfigAttrib(const Display *display, const Config *config, EGLint attribute) +{ + ANGLE_TRY(ValidateConfig(display, config)); + ANGLE_TRY(ValidateConfigAttribute(display, static_cast<EGLAttrib>(attribute))); + return NoError(); +} + +Error ValidateChooseConfig(const Display *display, + const AttributeMap &attribs, + EGLint configSize, + EGLint *numConfig) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateConfigAttributes(display, attribs)); + + if (numConfig == nullptr) + { + return EglBadParameter() << "num_config cannot be null."; + } + + return NoError(); +} + +Error ValidateGetConfigs(const Display *display, EGLint configSize, EGLint *numConfig) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (numConfig == nullptr) + { + return EglBadParameter() << "num_config cannot be null."; + } + + return NoError(); +} + +Error ValidateGetPlatformDisplay(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list) +{ + const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list); + return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap); +} + +Error ValidateGetPlatformDisplayEXT(EGLenum platform, + void *native_display, + const EGLint *attrib_list) +{ + const auto &attribMap = AttributeMap::CreateFromIntArray(attrib_list); + return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap); +} + +Error ValidateProgramCacheGetAttribANGLE(const Display *display, EGLenum attrib) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + switch (attrib) + { + case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE: + case EGL_PROGRAM_CACHE_SIZE_ANGLE: + break; + + default: + return EglBadParameter() << "Invalid program cache attribute."; + } + + return NoError(); +} + +Error ValidateProgramCacheQueryANGLE(const Display *display, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (index < 0 || index >= display->programCacheGetAttrib(EGL_PROGRAM_CACHE_SIZE_ANGLE)) + { + return EglBadParameter() << "Program index out of range."; + } + + if (keysize == nullptr || binarysize == nullptr) + { + return EglBadParameter() << "keysize and binarysize must always be valid pointers."; + } + + if (binary && *keysize != static_cast<EGLint>(gl::kProgramHashLength)) + { + return EglBadParameter() << "Invalid program key size."; + } + + if ((key == nullptr) != (binary == nullptr)) + { + return EglBadParameter() << "key and binary must both be null or both non-null."; + } + + return NoError(); +} + +Error ValidateProgramCachePopulateANGLE(const Display *display, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (keysize != static_cast<EGLint>(gl::kProgramHashLength)) + { + return EglBadParameter() << "Invalid program key size."; + } + + if (key == nullptr || binary == nullptr) + { + return EglBadParameter() << "null pointer in arguments."; + } + + // Upper bound for binarysize is arbitrary. + if (binarysize <= 0 || binarysize > egl::kProgramCacheSizeAbsoluteMax) + { + return EglBadParameter() << "binarysize out of valid range."; + } + + return NoError(); +} + +Error ValidateProgramCacheResizeANGLE(const Display *display, EGLint limit, EGLenum mode) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (limit < 0) + { + return EglBadParameter() << "limit must be non-negative."; + } + + switch (mode) + { + case EGL_PROGRAM_CACHE_RESIZE_ANGLE: + case EGL_PROGRAM_CACHE_TRIM_ANGLE: + break; + + default: + return EglBadParameter() << "Invalid cache resize mode."; + } + + return NoError(); +} + +Error ValidateSurfaceAttrib(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateSurface(display, surface)); + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE."; + } + + switch (attribute) + { + case EGL_MIPMAP_LEVEL: + break; + + case EGL_MULTISAMPLE_RESOLVE: + switch (value) + { + case EGL_MULTISAMPLE_RESOLVE_DEFAULT: + break; + + case EGL_MULTISAMPLE_RESOLVE_BOX: + if ((surface->getConfig()->surfaceType & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) == 0) + { + return EglBadMatch() + << "Surface does not support EGL_MULTISAMPLE_RESOLVE_BOX."; + } + break; + + default: + return EglBadAttribute() << "Invalid multisample resolve type."; + } + + case EGL_SWAP_BEHAVIOR: + switch (value) + { + case EGL_BUFFER_PRESERVED: + if ((surface->getConfig()->surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == 0) + { + return EglBadMatch() + << "Surface does not support EGL_SWAP_BEHAVIOR_PRESERVED."; + } + break; + + case EGL_BUFFER_DESTROYED: + break; + + default: + return EglBadAttribute() << "Invalid swap behaviour."; + } + + default: + return EglBadAttribute() << "Invalid surface attribute."; + } + + return NoError(); +} + +Error ValidateQuerySurface(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateSurface(display, surface)); + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE."; + } + + switch (attribute) + { + case EGL_GL_COLORSPACE: + case EGL_VG_ALPHA_FORMAT: + case EGL_VG_COLORSPACE: + case EGL_CONFIG_ID: + case EGL_HEIGHT: + case EGL_HORIZONTAL_RESOLUTION: + case EGL_LARGEST_PBUFFER: + case EGL_MIPMAP_TEXTURE: + case EGL_MIPMAP_LEVEL: + case EGL_MULTISAMPLE_RESOLVE: + case EGL_PIXEL_ASPECT_RATIO: + case EGL_RENDER_BUFFER: + case EGL_SWAP_BEHAVIOR: + case EGL_TEXTURE_FORMAT: + case EGL_TEXTURE_TARGET: + case EGL_VERTICAL_RESOLUTION: + case EGL_WIDTH: + break; + + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + if (!display->getExtensions().postSubBuffer) + { + return EglBadAttribute() << "EGL_POST_SUB_BUFFER_SUPPORTED_NV cannot be used " + "without EGL_ANGLE_surface_orientation support."; + } + break; + + case EGL_FIXED_SIZE_ANGLE: + if (!display->getExtensions().windowFixedSize) + { + return EglBadAttribute() << "EGL_FIXED_SIZE_ANGLE cannot be used without " + "EGL_ANGLE_window_fixed_size support."; + } + break; + + case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: + if (!display->getExtensions().flexibleSurfaceCompatibility) + { + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be " + "used without EGL_ANGLE_flexible_surface_compatibility support."; + } + break; + + case EGL_SURFACE_ORIENTATION_ANGLE: + if (!display->getExtensions().surfaceOrientation) + { + return EglBadAttribute() << "EGL_SURFACE_ORIENTATION_ANGLE cannot be " + "queried without " + "EGL_ANGLE_surface_orientation support."; + } + break; + + case EGL_DIRECT_COMPOSITION_ANGLE: + if (!display->getExtensions().directComposition) + { + return EglBadAttribute() << "EGL_DIRECT_COMPOSITION_ANGLE cannot be " + "used without " + "EGL_ANGLE_direct_composition support."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be " + "used without EGL_ANGLE_robust_resource_initialization " + "support."; + } + break; + + default: + return EglBadAttribute() << "Invalid surface attribute."; + } + + return NoError(); +} + +Error ValidateQueryContext(const Display *display, + const gl::Context *context, + EGLint attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateContext(display, context)); + + switch (attribute) + { + case EGL_CONFIG_ID: + case EGL_CONTEXT_CLIENT_TYPE: + case EGL_CONTEXT_CLIENT_VERSION: + case EGL_RENDER_BUFFER: + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be " + "used without EGL_ANGLE_robust_resource_initialization " + "support."; + } + break; + + default: + return EglBadAttribute() << "Invalid context attribute."; + } + + return NoError(); +} + +} // namespace egl |