diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/validationEGL.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 567 |
1 files changed, 563 insertions, 4 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp index 12ee6a2b93..903f51b158 100644 --- a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp @@ -8,13 +8,87 @@ #include "libANGLE/validationEGL.h" +#include "common/utilities.h" #include "libANGLE/Config.h" #include "libANGLE/Context.h" +#include "libANGLE/Device.h" #include "libANGLE/Display.h" +#include "libANGLE/Image.h" #include "libANGLE/Surface.h" #include <EGL/eglext.h> +namespace +{ +size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) +{ + const gl::Caps &caps = context->getCaps(); + + size_t maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: + maxDimension = caps.max2DTextureSize; + break; + case GL_TEXTURE_CUBE_MAP: + maxDimension = caps.maxCubeMapTextureSize; + break; + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + default: + UNREACHABLE(); + } + + return gl::log2(static_cast<int>(maxDimension)); +} + +bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::Texture *texture) +{ + size_t maxMip = GetMaximumMipLevel(context, texture->getTarget()); + for (size_t level = 1; level < maxMip; level++) + { + if (texture->getTarget() == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; + face++) + { + if (texture->getInternalFormat(face, level) != GL_NONE) + { + return true; + } + } + } + else + { + if (texture->getInternalFormat(texture->getTarget(), level) != GL_NONE) + { + return true; + } + } + } + + return false; +} + +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) + { + return true; + } + } + + return false; +} +} + namespace egl { @@ -22,12 +96,17 @@ Error ValidateDisplay(const Display *display) { if (display == EGL_NO_DISPLAY) { - return Error(EGL_BAD_DISPLAY); + return Error(EGL_BAD_DISPLAY, "display is EGL_NO_DISPLAY."); + } + + if (!Display::isValidDisplay(display)) + { + return Error(EGL_BAD_DISPLAY, "display is not a valid display."); } if (!display->isInitialized()) { - return Error(EGL_NOT_INITIALIZED); + return Error(EGL_NOT_INITIALIZED, "display is not initialized."); } return Error(EGL_SUCCESS); @@ -81,6 +160,22 @@ Error ValidateContext(const Display *display, gl::Context *context) return Error(EGL_SUCCESS); } +Error ValidateImage(const Display *display, const Image *image) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidImage(image)) + { + return Error(EGL_BAD_PARAMETER, "image is not valid."); + } + + return Error(EGL_SUCCESS); +} + Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, const AttributeMap& attributes) { @@ -115,6 +210,9 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context contextFlags = value; break; + case EGL_CONTEXT_OPENGL_DEBUG: + break; + case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: // Only valid for OpenGL (non-ES) contexts return Error(EGL_BAD_ATTRIBUTE); @@ -150,6 +248,17 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context } break; + case EGL_CONTEXT_OPENGL_NO_ERROR_KHR: + if (!display->getExtensions().createContextNoError) + { + return Error(EGL_BAD_ATTRIBUTE, "Invalid Context attribute."); + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return Error(EGL_BAD_ATTRIBUTE, "Attribute must be EGL_TRUE or EGL_FALSE."); + } + break; + default: return Error(EGL_BAD_ATTRIBUTE); } @@ -248,6 +357,13 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin } break; + case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: + if (!displayExtensions.flexibleSurfaceCompatibility) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + case EGL_WIDTH: case EGL_HEIGHT: if (!displayExtensions.windowFixedSize) @@ -267,12 +383,26 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin } break; + case EGL_SURFACE_ORIENTATION_ANGLE: + if (!displayExtensions.surfaceOrientation) + { + return Error(EGL_BAD_ATTRIBUTE, "EGL_ANGLE_surface_orientation is not enabled."); + } + break; + case EGL_VG_COLORSPACE: return Error(EGL_BAD_MATCH); case EGL_VG_ALPHA_FORMAT: return Error(EGL_BAD_MATCH); + case EGL_DIRECT_COMPOSITION_ANGLE: + if (!displayExtensions.directComposition) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + default: return Error(EGL_BAD_ATTRIBUTE); } @@ -293,7 +423,9 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri { return error; } - + + const DisplayExtensions &displayExtensions = display->getExtensions(); + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { EGLint attribute = attributeIter->first; @@ -344,6 +476,16 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_VG_ALPHA_FORMAT: break; + 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."); + } + break; + default: return Error(EGL_BAD_ATTRIBUTE); } @@ -354,6 +496,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri return Error(EGL_BAD_MATCH); } +#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); @@ -377,6 +520,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri { return Error(EGL_BAD_MATCH); } +#endif return Error(EGL_SUCCESS); } @@ -454,6 +598,16 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_MIPMAP_TEXTURE: break; + 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."); + } + break; + default: return Error(EGL_BAD_ATTRIBUTE); } @@ -488,7 +642,8 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E return Error(EGL_BAD_ATTRIBUTE); } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check +// 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))) { @@ -500,4 +655,408 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E return Error(EGL_SUCCESS); } +Error ValidateCompatibleConfigs(const Display *display, + const Config *config1, + const Surface *surface, + const Config *config2, + EGLint surfaceType) +{ + + if (!surface->flexibleSurfaceCompatibilityRequested()) + { + // Config compatibility is defined in section 2.2 of the EGL 1.5 spec + + bool colorBufferCompat = config1->colorBufferType == config2->colorBufferType; + if (!colorBufferCompat) + { + return Error(EGL_BAD_MATCH, "Color buffer types are not compatible."); + } + + bool colorCompat = + config1->redSize == config2->redSize && config1->greenSize == config2->greenSize && + config1->blueSize == config2->blueSize && config1->alphaSize == config2->alphaSize && + config1->luminanceSize == config2->luminanceSize; + if (!colorCompat) + { + return Error(EGL_BAD_MATCH, "Color buffer sizes 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."); + } + } + + bool surfaceTypeCompat = (config1->surfaceType & config2->surfaceType & surfaceType) != 0; + if (!surfaceTypeCompat) + { + return Error(EGL_BAD_MATCH, "Surface types are not compatible."); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreateImageKHR(const Display *display, + gl::Context *context, + EGLenum target, + EGLClientBuffer buffer, + const AttributeMap &attributes) +{ + Error error = ValidateContext(display, context); + if (error.isError()) + { + return error; + } + + const DisplayExtensions &displayExtensions = display->getExtensions(); + + if (!displayExtensions.imageBase && !displayExtensions.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, "EGL_KHR_image not supported."); + } + + // TODO(geofflang): Complete validation from EGL_KHR_image_base: + // If the resource specified by <dpy>, <ctx>, <target>, <buffer> and <attrib_list> is itself an + // EGLImage sibling, the error EGL_BAD_ACCESS is generated. + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); + attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_IMAGE_PRESERVED_KHR: + switch (value) + { + case EGL_TRUE: + case EGL_FALSE: + break; + + default: + return Error(EGL_BAD_PARAMETER, + "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."); + } + break; + + case EGL_GL_TEXTURE_LEVEL_KHR: + 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."); + } + + if (value < 0) + { + return Error(EGL_BAD_PARAMETER, "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."); + } + break; + + default: + return Error(EGL_BAD_PARAMETER, "invalid attribute: 0x%X", attribute); + } + } + + switch (target) + { + case EGL_GL_TEXTURE_2D_KHR: + { + if (!displayExtensions.glTexture2DImage) + { + return Error(EGL_BAD_PARAMETER, "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."); + } + + 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."); + } + + if (texture->getBoundSurface() != nullptr) + { + return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + } + + EGLint 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."); + } + + 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."); + } + } + break; + + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: + { + if (!displayExtensions.glTextureCubemapImage) + { + return Error(EGL_BAD_PARAMETER, "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."); + } + + 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."); + } + + if (texture->getBoundSurface() != nullptr) + { + return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + } + + EGLint 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."); + } + + 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."); + } + + 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."); + } + } + break; + + case EGL_GL_TEXTURE_3D_KHR: + { + if (!displayExtensions.glTexture3DImage) + { + return Error(EGL_BAD_PARAMETER, "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."); + } + + 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."); + } + + if (texture->getBoundSurface() != nullptr) + { + return Error(EGL_BAD_ACCESS, "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); + 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."); + } + + 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."); + } + + 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."); + } + } + break; + + case EGL_GL_RENDERBUFFER_KHR: + { + if (!displayExtensions.glRenderbufferImage) + { + return Error(EGL_BAD_PARAMETER, "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."); + } + + if (buffer == 0) + { + return Error(EGL_BAD_PARAMETER, + "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."); + } + + if (renderbuffer->getSamples() > 0) + { + return Error(EGL_BAD_PARAMETER, "target renderbuffer cannot be multisampled."); + } + } + break; + + default: + return Error(EGL_BAD_PARAMETER, "invalid target: 0x%X", target); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateDestroyImageKHR(const Display *display, const Image *image) +{ + Error error = ValidateImage(display, image); + if (error.isError()) + { + return error; + } + + 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 Error(EGL_SUCCESS); +} + +Error ValidateCreateDeviceANGLE(EGLint device_type, + void *native_device, + const EGLAttrib *attrib_list) +{ + const ClientExtensions &clientExtensions = Display::getClientExtensions(); + if (!clientExtensions.deviceCreation) + { + return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + } + + if (attrib_list != nullptr && attrib_list[0] != EGL_NONE) + { + return Error(EGL_BAD_ATTRIBUTE, "Invalid attrib_list parameter"); + } + + switch (device_type) + { + case EGL_D3D11_DEVICE_ANGLE: + if (!clientExtensions.deviceCreationD3D11) + { + return Error(EGL_BAD_ATTRIBUTE, "D3D11 device creation extension not active"); + } + break; + default: + return Error(EGL_BAD_ATTRIBUTE, "Invalid device_type parameter"); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateReleaseDeviceANGLE(Device *device) +{ + const ClientExtensions &clientExtensions = Display::getClientExtensions(); + if (!clientExtensions.deviceCreation) + { + return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + } + + if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device)) + { + return Error(EGL_BAD_DEVICE_EXT, "Invalid device parameter"); + } + + Display *owningDisplay = device->getOwningDisplay(); + if (owningDisplay != nullptr) + { + return Error(EGL_BAD_DEVICE_EXT, "Device must have been created using eglCreateDevice"); + } + + return Error(EGL_SUCCESS); +} } |