Surface::Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes) : FramebufferAttachmentObject(), mImplementation(impl), mCurrentCount(0), mDestroyed(false), mType(surfaceType), mConfig(config), mPostSubBufferRequested(false), mFixedSize(false), mFixedWidth(0), mFixedHeight(0), mTextureFormat(EGL_NO_TEXTURE), mTextureTarget(EGL_NO_TEXTURE), // FIXME: Determine actual pixel aspect ratio mPixelAspectRatio(static_cast<EGLint>(1.0 * EGL_DISPLAY_SCALING)), mRenderBuffer(EGL_BACK_BUFFER), mSwapBehavior(impl->getSwapBehavior()) { mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); if (mFixedSize) { mFixedWidth = attributes.get(EGL_WIDTH, 0); mFixedHeight = attributes.get(EGL_HEIGHT, 0); } if (mType != EGL_WINDOW_BIT) { mTextureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); mTextureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); } }
Image::Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs) : RefCountObject(0), mImplementation(impl), mInternalFormat(GL_NONE), mWidth(0), mHeight(0), mSamples(0), mSource(), mTargets() { ASSERT(mImplementation != nullptr); ASSERT(buffer != nullptr); mSource.set(buffer); mSource->addImageSource(this); if (IsTextureTarget(target)) { gl::Texture *texture = rx::GetAs<gl::Texture>(mSource.get()); GLenum textureTarget = egl_gl::EGLImageTargetToGLTextureTarget(target); size_t level = attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); mInternalFormat = texture->getInternalFormat(textureTarget, level); mWidth = texture->getWidth(textureTarget, level); mHeight = texture->getHeight(textureTarget, level); mSamples = 0; } else if (IsRenderbufferTarget(target)) { gl::Renderbuffer *renderbuffer = rx::GetAs<gl::Renderbuffer>(mSource.get()); mInternalFormat = renderbuffer->getInternalFormat(); mWidth = renderbuffer->getWidth(); mHeight = renderbuffer->getHeight(); mSamples = renderbuffer->getSamples(); } else { UNREACHABLE(); } }
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 ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes) { Error error = ValidateConfig(display, config); if (error.isError()) { return error; } const DisplayExtensions &displayExtensions = display->getExtensions(); switch (buftype) { case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: if (!displayExtensions.d3dShareHandleClientBuffer) { return Error(EGL_BAD_PARAMETER); } if (buffer == nullptr) { return Error(EGL_BAD_PARAMETER); } break; default: return Error(EGL_BAD_PARAMETER); } for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { EGLint attribute = attributeIter->first; EGLint value = attributeIter->second; switch (attribute) { case EGL_WIDTH: case EGL_HEIGHT: if (!displayExtensions.d3dShareHandleClientBuffer) { return Error(EGL_BAD_PARAMETER); } if (value < 0) { return Error(EGL_BAD_PARAMETER); } break; case EGL_TEXTURE_FORMAT: switch (value) { case EGL_NO_TEXTURE: case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGBA: break; default: return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_TEXTURE_TARGET: switch (value) { case EGL_NO_TEXTURE: case EGL_TEXTURE_2D: break; default: return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_MIPMAP_TEXTURE: break; default: return Error(EGL_BAD_ATTRIBUTE); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { return Error(EGL_BAD_MATCH); } EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); EGLenum 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); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { return Error(EGL_BAD_ATTRIBUTE); } if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) { EGLint width = attributes.get(EGL_WIDTH, 0); EGLint height = attributes.get(EGL_HEIGHT, 0); if (width == 0 || height == 0) { return Error(EGL_BAD_ATTRIBUTE); } const Caps &caps = display->getCaps(); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { return Error(EGL_BAD_MATCH); } } return Error(EGL_SUCCESS); }
Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes) { Error error = ValidateConfig(display, config); if (error.isError()) { return error; } for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { EGLint attribute = attributeIter->first; EGLint value = attributeIter->second; switch (attribute) { case EGL_WIDTH: case EGL_HEIGHT: if (value < 0) { return Error(EGL_BAD_PARAMETER); } break; case EGL_LARGEST_PBUFFER: break; case EGL_TEXTURE_FORMAT: switch (value) { case EGL_NO_TEXTURE: case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGBA: break; default: return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_TEXTURE_TARGET: switch (value) { case EGL_NO_TEXTURE: case EGL_TEXTURE_2D: break; default: return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_MIPMAP_TEXTURE: break; case EGL_VG_COLORSPACE: break; case EGL_VG_ALPHA_FORMAT: break; default: return Error(EGL_BAD_ATTRIBUTE); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { return Error(EGL_BAD_MATCH); } 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); if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { return Error(EGL_BAD_MATCH); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { return Error(EGL_BAD_ATTRIBUTE); } EGLint width = attributes.get(EGL_WIDTH, 0); EGLint height = attributes.get(EGL_HEIGHT, 0); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { return Error(EGL_BAD_MATCH); } return Error(EGL_SUCCESS); }
Surface::Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes, EGLenum buftype) : FramebufferAttachmentObject(), mState(config, attributes), mImplementation(nullptr), mRefCount(0), mDestroyed(false), mType(surfaceType), mBuftype(buftype), mPostSubBufferRequested(false), mLargestPbuffer(false), mGLColorspace(EGL_GL_COLORSPACE_LINEAR), mVGAlphaFormat(EGL_VG_ALPHA_FORMAT_NONPRE), mVGColorspace(EGL_VG_COLORSPACE_sRGB), mMipmapTexture(false), mMipmapLevel(0), mHorizontalResolution(EGL_UNKNOWN), mVerticalResolution(EGL_UNKNOWN), mMultisampleResolve(EGL_MULTISAMPLE_RESOLVE_DEFAULT), mFixedSize(false), mFixedWidth(0), mFixedHeight(0), mTextureFormat(TextureFormat::NoTexture), mTextureTarget(EGL_NO_TEXTURE), // FIXME: Determine actual pixel aspect ratio mPixelAspectRatio(static_cast<EGLint>(1.0 * EGL_DISPLAY_SCALING)), mRenderBuffer(EGL_BACK_BUFFER), mSwapBehavior(EGL_NONE), mOrientation(0), mTexture(nullptr), mColorFormat(config->renderTargetFormat), mDSFormat(config->depthStencilFormat), mInitState(gl::InitState::Initialized) { mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); mFlexibleSurfaceCompatibilityRequested = (attributes.get(EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_FALSE) == EGL_TRUE); if (mType == EGL_PBUFFER_BIT) { mLargestPbuffer = (attributes.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); } mGLColorspace = static_cast<EGLenum>(attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR)); mVGAlphaFormat = static_cast<EGLenum>(attributes.get(EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_NONPRE)); mVGColorspace = static_cast<EGLenum>(attributes.get(EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB)); mMipmapTexture = (attributes.get(EGL_MIPMAP_TEXTURE, EGL_FALSE) == EGL_TRUE); mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); mRobustResourceInitialization = (attributes.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE); if (mRobustResourceInitialization) { mInitState = gl::InitState::MayNeedInit; } mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); if (mFixedSize) { mFixedWidth = static_cast<size_t>(attributes.get(EGL_WIDTH, 0)); mFixedHeight = static_cast<size_t>(attributes.get(EGL_HEIGHT, 0)); } if (mType != EGL_WINDOW_BIT) { mTextureFormat = attributes.getAsPackedEnum(EGL_TEXTURE_FORMAT, TextureFormat::NoTexture); mTextureTarget = static_cast<EGLenum>(attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE)); } mOrientation = static_cast<EGLint>(attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0)); }
Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes) { ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); switch (buftype) { case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: if (!displayExtensions.d3dShareHandleClientBuffer) { return Error(EGL_BAD_PARAMETER); } if (buffer == nullptr) { return Error(EGL_BAD_PARAMETER); } break; default: return Error(EGL_BAD_PARAMETER); } for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { EGLAttrib attribute = attributeIter->first; EGLAttrib value = attributeIter->second; switch (attribute) { case EGL_WIDTH: case EGL_HEIGHT: if (!displayExtensions.d3dShareHandleClientBuffer) { return Error(EGL_BAD_PARAMETER); } if (value < 0) { return Error(EGL_BAD_PARAMETER); } break; case EGL_TEXTURE_FORMAT: switch (value) { case EGL_NO_TEXTURE: case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGBA: break; default: return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_TEXTURE_TARGET: switch (value) { case EGL_NO_TEXTURE: case EGL_TEXTURE_2D: break; default: return Error(EGL_BAD_ATTRIBUTE); } break; 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); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { return Error(EGL_BAD_MATCH); } 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); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { return Error(EGL_BAD_ATTRIBUTE); } if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) { 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); } const Caps &caps = display->getCaps(); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { return Error(EGL_BAD_MATCH); } } return Error(EGL_SUCCESS); }