// // Copyright 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SurfaceEGL.cpp: EGL implementation of egl::Surface #include "libANGLE/renderer/gl/egl/SurfaceEGL.h" #include "common/debug.h" namespace rx { SurfaceEGL::SurfaceEGL(const egl::SurfaceState &state, const FunctionsEGL *egl, EGLConfig config) : SurfaceGL(state), mEGL(egl), mConfig(config), mSurface(EGL_NO_SURFACE), mHasSwapBuffersWithDamage(mEGL->hasExtension("EGL_KHR_swap_buffers_with_damage")) {} SurfaceEGL::~SurfaceEGL() { if (mSurface != EGL_NO_SURFACE) { EGLBoolean success = mEGL->destroySurface(mSurface); ASSERT(success == EGL_TRUE); } } egl::Error SurfaceEGL::makeCurrent(const gl::Context *context) { // Handling of makeCurrent is done in DisplayEGL return egl::NoError(); } egl::Error SurfaceEGL::swap(const gl::Context *context) { EGLBoolean success = mEGL->swapBuffers(mSurface); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglSwapBuffers failed"); } return egl::NoError(); } egl::Error SurfaceEGL::swapWithDamage(const gl::Context *context, const EGLint *rects, EGLint n_rects) { EGLBoolean success; if (mHasSwapBuffersWithDamage) { success = mEGL->swapBuffersWithDamageKHR(mSurface, rects, n_rects); } else { success = mEGL->swapBuffers(mSurface); } if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglSwapBuffersWithDamageKHR failed"); } return egl::NoError(); } egl::Error SurfaceEGL::postSubBuffer(const gl::Context *context, EGLint x, EGLint y, EGLint width, EGLint height) { UNIMPLEMENTED(); return egl::EglBadSurface(); } egl::Error SurfaceEGL::setPresentationTime(EGLnsecsANDROID time) { EGLBoolean success = mEGL->presentationTimeANDROID(mSurface, time); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglPresentationTimeANDROID failed"); } return egl::NoError(); } egl::Error SurfaceEGL::querySurfacePointerANGLE(EGLint attribute, void **value) { UNIMPLEMENTED(); return egl::EglBadSurface(); } egl::Error SurfaceEGL::bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer) { EGLBoolean success = mEGL->bindTexImage(mSurface, buffer); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglBindTexImage failed"); } return egl::NoError(); } egl::Error SurfaceEGL::releaseTexImage(const gl::Context *context, EGLint buffer) { EGLBoolean success = mEGL->releaseTexImage(mSurface, buffer); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglReleaseTexImage failed"); } return egl::NoError(); } void SurfaceEGL::setSwapInterval(EGLint interval) { EGLBoolean success = mEGL->swapInterval(interval); if (success == EGL_FALSE) { ERR() << "eglSwapInterval error " << egl::Error(mEGL->getError()); ASSERT(false); } } EGLint SurfaceEGL::getWidth() const { EGLint value; EGLBoolean success = mEGL->querySurface(mSurface, EGL_WIDTH, &value); ASSERT(success == EGL_TRUE); return value; } EGLint SurfaceEGL::getHeight() const { EGLint value; EGLBoolean success = mEGL->querySurface(mSurface, EGL_HEIGHT, &value); ASSERT(success == EGL_TRUE); return value; } EGLint SurfaceEGL::isPostSubBufferSupported() const { UNIMPLEMENTED(); return 0; } EGLint SurfaceEGL::getSwapBehavior() const { EGLint value; EGLBoolean success = mEGL->querySurface(mSurface, EGL_SWAP_BEHAVIOR, &value); ASSERT(success == EGL_TRUE); return value; } EGLSurface SurfaceEGL::getSurface() const { return mSurface; } void SurfaceEGL::setTimestampsEnabled(bool enabled) { ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps")); EGLBoolean success = mEGL->surfaceAttrib(mSurface, EGL_TIMESTAMPS_ANDROID, enabled ? EGL_TRUE : EGL_FALSE); if (success == EGL_FALSE) { ERR() << "eglSurfaceAttribute failed: " << egl::Error(mEGL->getError()); } } egl::SupportedCompositorTimings SurfaceEGL::getSupportedCompositorTimings() const { ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps")); egl::SupportedCompositorTimings result; for (egl::CompositorTiming name : angle::AllEnums()) { result[name] = mEGL->getCompositorTimingSupportedANDROID(mSurface, egl::ToEGLenum(name)); } return result; } egl::Error SurfaceEGL::getCompositorTiming(EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) const { ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps")); EGLBoolean success = mEGL->getCompositorTimingANDROID(mSurface, numTimestamps, names, values); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglGetCompositorTimingANDROID failed"); } return egl::NoError(); } egl::Error SurfaceEGL::getNextFrameId(EGLuint64KHR *frameId) const { ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps")); EGLBoolean success = mEGL->getNextFrameIdANDROID(mSurface, frameId); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglGetNextFrameId failed"); } return egl::NoError(); } egl::SupportedTimestamps SurfaceEGL::getSupportedTimestamps() const { ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps")); egl::SupportedTimestamps result; for (egl::Timestamp timestamp : angle::AllEnums()) { result[timestamp] = mEGL->getFrameTimestampSupportedANDROID(mSurface, egl::ToEGLenum(timestamp)); } return result; } egl::Error SurfaceEGL::getFrameTimestamps(EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values) const { ASSERT(mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps")); // The driver may return EGL_BAD_ACCESS at any time if the requested frame is no longer stored. EGLBoolean success = mEGL->getFrameTimestampsANDROID(mSurface, frameId, numTimestamps, timestamps, values); if (success == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglGetFrameTimestampsANDROID failed"); } return egl::NoError(); } bool SurfaceEGL::isExternal() const { return false; } } // namespace rx