EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); Display *display = static_cast<Display*>(dpy); gl::Context *context = static_cast<gl::Context*>(ctx); Error error = ValidateContext(display, context); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } if (ctx == EGL_NO_CONTEXT) { SetGlobalError(Error(EGL_BAD_CONTEXT)); return EGL_FALSE; } if (context == GetGlobalContext()) { SetGlobalDisplay(NULL); SetGlobalContext(NULL); } display->destroyContext(context); SetGlobalError(Error(EGL_SUCCESS)); return EGL_TRUE; }
Error ValidateStreamConsumerAcquireKHR(const Display *display, gl::Context *context, const Stream *stream) { ANGLE_TRY(ValidateDisplay(display)); const DisplayExtensions &displayExtensions = display->getExtensions(); if (!displayExtensions.streamConsumerGLTexture) { return Error(EGL_BAD_ACCESS, "Stream consumer extension not active"); } if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { return Error(EGL_BAD_STREAM_KHR, "Invalid stream"); } if (!context) { return Error(EGL_BAD_ACCESS, "No GL context current to calling thread."); } ANGLE_TRY(ValidateContext(display, context)); if (!stream->isConsumerBoundToContext(context)) { return Error(EGL_BAD_ACCESS, "Current GL context not associated with stream consumer"); } if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) { return Error(EGL_BAD_ACCESS, "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 Error(EGL_BAD_STATE_KHR, "Invalid stream state"); } return Error(EGL_SUCCESS); }
Error ValidateStreamConsumerReleaseKHR(const Display *display, gl::Context *context, const Stream *stream) { ANGLE_TRY(ValidateDisplay(display)); const DisplayExtensions &displayExtensions = display->getExtensions(); if (!displayExtensions.streamConsumerGLTexture) { return Error(EGL_BAD_ACCESS, "Stream consumer extension not active"); } if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { return Error(EGL_BAD_STREAM_KHR, "Invalid stream"); } if (!context) { return Error(EGL_BAD_ACCESS, "No GL context current to calling thread."); } ANGLE_TRY(ValidateContext(display, context)); if (!stream->isConsumerBoundToContext(context)) { return Error(EGL_BAD_ACCESS, "Current GL context not associated with stream consumer"); } if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) { return Error(EGL_BAD_ACCESS, "Invalid stream consumer type"); } if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) { return Error(EGL_BAD_STATE_KHR, "Invalid stream state"); } return Error(EGL_SUCCESS); }
EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", dpy, ctx, attribute, value); Display *display = static_cast<Display*>(dpy); gl::Context *context = static_cast<gl::Context*>(ctx); Error error = ValidateContext(display, context); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } switch (attribute) { case EGL_CONFIG_ID: *value = context->getConfig()->configID; break; case EGL_CONTEXT_CLIENT_TYPE: *value = context->getClientType(); break; case EGL_CONTEXT_CLIENT_VERSION: *value = context->getClientVersion(); break; case EGL_RENDER_BUFFER: *value = context->getRenderBuffer(); break; default: SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); return EGL_FALSE; } SetGlobalError(Error(EGL_SUCCESS)); return EGL_TRUE; }
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 Error(EGL_BAD_ACCESS, "Stream consumer extension not active"); } if (!context->getExtensions().eglStreamConsumerExternal) { return Error(EGL_BAD_ACCESS, "EGL stream consumer external GL extension not enabled"); } if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { return Error(EGL_BAD_STREAM_KHR, "Invalid stream"); } if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) { return Error(EGL_BAD_STATE_KHR, "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 Error(EGL_BAD_ACCESS, "No external texture bound"); } return Error(EGL_SUCCESS); }
EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); Thread *thread = GetCurrentThread(); Display *display = static_cast<Display *>(dpy); gl::Context *context = static_cast<gl::Context *>(ctx); Error error = ValidateContext(display, context); if (error.isError()) { thread->setError(error); return EGL_FALSE; } if (ctx == EGL_NO_CONTEXT) { thread->setError(EglBadContext()); return EGL_FALSE; } if (context == thread->getContext()) { thread->setCurrent(nullptr); } error = display->destroyContext(context); if (error.isError()) { thread->setError(error); return EGL_FALSE; } thread->setError(NoError()); return EGL_TRUE; }
EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, draw, read, ctx); Display *display = static_cast<Display*>(dpy); gl::Context *context = static_cast<gl::Context*>(ctx); // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH // error is generated. if (ctx == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) { SetGlobalError(Error(EGL_BAD_MATCH)); return EGL_FALSE; } if (ctx != EGL_NO_CONTEXT && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE) { SetGlobalError(Error(EGL_BAD_MATCH)); return EGL_FALSE; } // 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)) { SetGlobalError(Error( EGL_BAD_MATCH, "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE")); return EGL_FALSE; } if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) { SetGlobalError(Error(EGL_BAD_DISPLAY, "'dpy' not a valid EGLDisplay handle")); return EGL_FALSE; } // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null if (!display->isInitialized() && (ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) { SetGlobalError(Error(EGL_NOT_INITIALIZED, "'dpy' not initialized")); return EGL_FALSE; } if (ctx != EGL_NO_CONTEXT) { Error error = ValidateContext(display, context); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } if (display->isInitialized()) { if (display->testDeviceLost()) { display->notifyDeviceLost(); return EGL_FALSE; } if (display->isDeviceLost()) { SetGlobalError(Error(EGL_CONTEXT_LOST)); return EGL_FALSE; } } Surface *drawSurface = static_cast<Surface*>(draw); if (draw != EGL_NO_SURFACE) { Error error = ValidateSurface(display, drawSurface); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } Surface *readSurface = static_cast<Surface*>(read); if (read != EGL_NO_SURFACE) { Error error = ValidateSurface(display, readSurface); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } if (readSurface) { Error readCompatError = ValidateCompatibleConfigs(readSurface->getConfig(), context->getConfig(), readSurface->getType()); if (readCompatError.isError()) { SetGlobalError(readCompatError); return EGL_FALSE; } } if (draw != read) { UNIMPLEMENTED(); // FIXME if (drawSurface) { Error drawCompatError = ValidateCompatibleConfigs(drawSurface->getConfig(), context->getConfig(), drawSurface->getType()); if (drawCompatError.isError()) { SetGlobalError(drawCompatError); return EGL_FALSE; } } } Error makeCurrentError = display->makeCurrent(drawSurface, readSurface, context); if (makeCurrentError.isError()) { SetGlobalError(makeCurrentError); return EGL_FALSE; } gl::Context *previousContext = GetGlobalContext(); SetGlobalDisplay(display); SetGlobalDrawSurface(drawSurface); SetGlobalReadSurface(readSurface); SetGlobalContext(context); // Release the surface from the previously-current context, to allow // destroyed surfaces to delete themselves. if (previousContext != nullptr && context != previousContext) { previousContext->releaseSurface(); } SetGlobalError(Error(EGL_SUCCESS)); return EGL_TRUE; }
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); }
EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, draw, read, ctx); Display *display = static_cast<Display*>(dpy); gl::Context *context = static_cast<gl::Context*>(ctx); bool noContext = (ctx == EGL_NO_CONTEXT); bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE); if (noContext != noSurface) { SetGlobalError(Error(EGL_BAD_MATCH)); return EGL_FALSE; } if (ctx != EGL_NO_CONTEXT) { Error error = ValidateContext(display, context); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } if (dpy != EGL_NO_DISPLAY && display->isInitialized()) { if (display->testDeviceLost()) { display->notifyDeviceLost(); return EGL_FALSE; } if (display->isDeviceLost()) { SetGlobalError(Error(EGL_CONTEXT_LOST)); return EGL_FALSE; } } Surface *drawSurface = static_cast<Surface*>(draw); if (draw != EGL_NO_SURFACE) { Error error = ValidateSurface(display, drawSurface); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } Surface *readSurface = static_cast<Surface*>(read); if (read != EGL_NO_SURFACE) { Error error = ValidateSurface(display, readSurface); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } if (draw != read) { UNIMPLEMENTED(); // FIXME } SetGlobalDisplay(display); SetGlobalDrawSurface(drawSurface); SetGlobalReadSurface(readSurface); SetGlobalContext(context); if (context != nullptr && display != nullptr && drawSurface != nullptr) { display->makeCurrent(drawSurface, readSurface, context); } SetGlobalError(Error(EGL_SUCCESS)); return EGL_TRUE; }
EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, draw, read, ctx); Display *display = static_cast<Display*>(dpy); gl::Context *context = static_cast<gl::Context*>(ctx); bool noContext = (ctx == EGL_NO_CONTEXT); bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE); if (noContext != noSurface) { SetGlobalError(Error(EGL_BAD_MATCH)); return EGL_FALSE; } if (dpy == EGL_NO_DISPLAY) { SetGlobalError(Error(EGL_BAD_DISPLAY, "'dpy' not a valid EGLDisplay handle")); return EGL_FALSE; } // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null if (dpy != EGL_NO_DISPLAY && !display->isInitialized() && (ctx != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) { SetGlobalError(Error(EGL_NOT_INITIALIZED, "'dpy' not initialized")); return EGL_FALSE; } if (ctx != EGL_NO_CONTEXT) { Error error = ValidateContext(display, context); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } if (dpy != EGL_NO_DISPLAY && display->isInitialized()) { if (display->testDeviceLost()) { display->notifyDeviceLost(); return EGL_FALSE; } if (display->isDeviceLost()) { SetGlobalError(Error(EGL_CONTEXT_LOST)); return EGL_FALSE; } } Surface *drawSurface = static_cast<Surface*>(draw); if (draw != EGL_NO_SURFACE) { Error error = ValidateSurface(display, drawSurface); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } Surface *readSurface = static_cast<Surface*>(read); if (read != EGL_NO_SURFACE) { Error error = ValidateSurface(display, readSurface); if (error.isError()) { SetGlobalError(error); return EGL_FALSE; } } if (draw != read) { UNIMPLEMENTED(); // FIXME } gl::Context *previousContext = GetGlobalContext(); SetGlobalDisplay(display); SetGlobalDrawSurface(drawSurface); SetGlobalReadSurface(readSurface); SetGlobalContext(context); display->makeCurrent(drawSurface, readSurface, context); // Release the surface from the previously-current context, to allow // destroyed surfaces to delete themselves. if (previousContext != nullptr && context != previousContext) { previousContext->releaseSurface(); } SetGlobalError(Error(EGL_SUCCESS)); return EGL_TRUE; }
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 Error(EGL_BAD_ACCESS, "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 Error(EGL_BAD_ACCESS, "EGL stream consumer external GL extension not enabled"); } if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { return Error(EGL_BAD_STREAM_KHR, "Invalid stream"); } if (!context) { return Error(EGL_BAD_ACCESS, "No GL context current to calling thread."); } ANGLE_TRY(ValidateContext(display, context)); if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) { return Error(EGL_BAD_STATE_KHR, "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 Error(EGL_BAD_PARAMETER, "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 Error(EGL_BAD_MATCH, "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 Error(EGL_BAD_ACCESS, "Invalid texture unit"); } plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value; } else { return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute"); } } } if (colorBufferType == EGL_RGB_BUFFER) { if (planeCount > 0) { return Error(EGL_BAD_MATCH, "Plane count must be 0 for RGB buffer"); } for (int i = 0; i < 3; i++) { if (plane[i] != -1) { return Error(EGL_BAD_MATCH, "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 Error(EGL_BAD_ACCESS, "No external texture bound"); } } else { if (planeCount == -1) { planeCount = 2; } if (planeCount < 1 || planeCount > 3) { return Error(EGL_BAD_MATCH, "Invalid YUV plane count"); } for (EGLAttrib i = planeCount; i < 3; i++) { if (plane[i] != -1) { return Error(EGL_BAD_MATCH, "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 Error(EGL_BAD_MATCH, "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 Error( EGL_BAD_ACCESS, "No external texture bound at one or more specified texture units"); } if (textureSet.find(texture) != textureSet.end()) { return Error(EGL_BAD_ACCESS, "Multiple planes bound to same texture object"); } textureSet.insert(texture); } } } return Error(EGL_SUCCESS); }