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;
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}
Beispiel #5
0
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;
}
Beispiel #8
0
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);
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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);
}