diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/egl')
19 files changed, 2945 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp new file mode 100755 index 000000000..988b233b4 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 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. +// + +// DisplayEGL.cpp: Common across EGL parts of platform specific egl::Display implementations + +#include "libANGLE/renderer/gl/egl/DisplayEGL.h" + +namespace rx +{ + +#define EGL_NO_CONFIG ((EGLConfig)0) + +DisplayEGL::DisplayEGL() + : DisplayGL(), + mEGL(nullptr), + mConfig(EGL_NO_CONFIG), + mContext(EGL_NO_CONTEXT), + mFunctionsGL(nullptr) +{ +} + +DisplayEGL::~DisplayEGL() +{ +} + +std::string DisplayEGL::getVendorString() const +{ + const char *vendor = mEGL->queryString(EGL_VENDOR); + ASSERT(vendor); + return vendor; +} + +egl::Error DisplayEGL::initializeContext(const egl::AttributeMap &eglAttributes) +{ + gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion); + + EGLint requestedMajor = + eglAttributes.getAsInt(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); + EGLint requestedMinor = + eglAttributes.getAsInt(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); + bool initializeRequested = requestedMajor != EGL_DONT_CARE && requestedMinor != EGL_DONT_CARE; + + static_assert(EGL_CONTEXT_MAJOR_VERSION == EGL_CONTEXT_MAJOR_VERSION_KHR, + "Major Version define should match"); + static_assert(EGL_CONTEXT_MINOR_VERSION == EGL_CONTEXT_MINOR_VERSION_KHR, + "Minor Version define should match"); + + std::vector<std::vector<EGLint>> contextAttribLists; + if (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context")) + { + if (initializeRequested) + { + contextAttribLists.push_back({EGL_CONTEXT_MAJOR_VERSION, requestedMajor, + EGL_CONTEXT_MINOR_VERSION, requestedMinor, EGL_NONE}); + } + else + { + // clang-format off + const gl::Version esVersionsFrom2_0[] = { + gl::Version(3, 2), + gl::Version(3, 1), + gl::Version(3, 0), + gl::Version(2, 0), + }; + // clang-format on + + for (const auto &version : esVersionsFrom2_0) + { + contextAttribLists.push_back( + {EGL_CONTEXT_MAJOR_VERSION, static_cast<EGLint>(version.major), + EGL_CONTEXT_MINOR_VERSION, static_cast<EGLint>(version.minor), EGL_NONE}); + } + } + } + else + { + if (initializeRequested && (requestedMajor != 2 || requestedMinor != 0)) + { + return egl::Error(EGL_BAD_ATTRIBUTE, "Unsupported requested context version"); + } + contextAttribLists.push_back({EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}); + } + + for (auto &attribList : contextAttribLists) + { + mContext = mEGL->createContext(mConfig, EGL_NO_CONTEXT, attribList.data()); + if (mContext != EGL_NO_CONTEXT) + { + return egl::Error(EGL_SUCCESS); + } + } + + return egl::Error(mEGL->getError(), "eglCreateContext failed"); +} + +void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const +{ + outExtensions->createContextRobustness = + mEGL->hasExtension("EGL_EXT_create_context_robustness"); + + outExtensions->postSubBuffer = false; // Since SurfaceEGL::postSubBuffer is not implemented +} + +void DisplayEGL::generateCaps(egl::Caps *outCaps) const +{ + outCaps->textureNPOT = true; // Since we request GLES >= 2 +} + +const FunctionsGL *DisplayEGL::getFunctionsGL() const +{ + return mFunctionsGL; +} +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/DisplayEGL.h b/gfx/angle/src/libANGLE/renderer/gl/egl/DisplayEGL.h new file mode 100755 index 000000000..e498cd79a --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/DisplayEGL.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 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. +// + +// DisplayEGL.h: Common across EGL parts of platform specific egl::Display implementations + +#ifndef LIBANGLE_RENDERER_GL_EGL_DISPLAYEGL_H_ +#define LIBANGLE_RENDERER_GL_EGL_DISPLAYEGL_H_ + +#include "libANGLE/renderer/gl/DisplayGL.h" +#include "libANGLE/renderer/gl/egl/FunctionsEGL.h" + +namespace rx +{ + +class DisplayEGL : public DisplayGL +{ + public: + DisplayEGL(); + ~DisplayEGL() override; + + std::string getVendorString() const override; + + protected: + egl::Error initializeContext(const egl::AttributeMap &eglAttributes); + + FunctionsEGL *mEGL; + EGLConfig mConfig; + EGLContext mContext; + FunctionsGL *mFunctionsGL; + + private: + void generateExtensions(egl::DisplayExtensions *outExtensions) const override; + void generateCaps(egl::Caps *outCaps) const override; + + const FunctionsGL *getFunctionsGL() const override; +}; + +} // namespace rx + +#endif /* LIBANGLE_RENDERER_GL_EGL_DISPLAYEGL_H_ */ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp new file mode 100755 index 000000000..c0b0f846f --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp @@ -0,0 +1,340 @@ +// +// Copyright (c) 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. +// + +// FunctionsEGL.cpp: Implements the FunctionsEGL class. + +#include "libANGLE/renderer/gl/egl/FunctionsEGL.h" + +#include <algorithm> + +#include "libANGLE/renderer/gl/FunctionsGL.h" +#include "libANGLE/renderer/gl/egl/functionsegl_typedefs.h" +#include "common/string_utils.h" + +namespace +{ + +template <typename T> +bool SetPtr(T *dst, void *src) +{ + if (src) + { + *dst = reinterpret_cast<T>(src); + return true; + } + return false; +} +} // namespace + +namespace rx +{ + +struct FunctionsEGL::EGLDispatchTable +{ + EGLDispatchTable() + : bindAPIPtr(nullptr), + chooseConfigPtr(nullptr), + createContextPtr(nullptr), + createPbufferSurfacePtr(nullptr), + createWindowSurfacePtr(nullptr), + destroyContextPtr(nullptr), + destroySurfacePtr(nullptr), + getConfigAttribPtr(nullptr), + getDisplayPtr(nullptr), + getErrorPtr(nullptr), + initializePtr(nullptr), + makeCurrentPtr(nullptr), + queryStringPtr(nullptr), + querySurfacePtr(nullptr), + swapBuffersPtr(nullptr), + terminatePtr(nullptr), + + bindTexImagePtr(nullptr), + releaseTexImagePtr(nullptr), + swapIntervalPtr(nullptr), + + createImageKHRPtr(nullptr), + destroyImageKHRPtr(nullptr), + + clientWaitSyncKHRPtr(nullptr), + createSyncKHRPtr(nullptr), + destroySyncKHRPtr(nullptr), + getSyncAttribKHRPtr(nullptr) + { + } + + // 1.0 + PFNEGLBINDAPIPROC bindAPIPtr; + PFNEGLCHOOSECONFIGPROC chooseConfigPtr; + PFNEGLCREATECONTEXTPROC createContextPtr; + PFNEGLCREATEPBUFFERSURFACEPROC createPbufferSurfacePtr; + PFNEGLCREATEWINDOWSURFACEPROC createWindowSurfacePtr; + PFNEGLDESTROYCONTEXTPROC destroyContextPtr; + PFNEGLDESTROYSURFACEPROC destroySurfacePtr; + PFNEGLGETCONFIGATTRIBPROC getConfigAttribPtr; + PFNEGLGETDISPLAYPROC getDisplayPtr; + PFNEGLGETERRORPROC getErrorPtr; + PFNEGLINITIALIZEPROC initializePtr; + PFNEGLMAKECURRENTPROC makeCurrentPtr; + PFNEGLQUERYSTRINGPROC queryStringPtr; + PFNEGLQUERYSURFACEPROC querySurfacePtr; + PFNEGLSWAPBUFFERSPROC swapBuffersPtr; + PFNEGLTERMINATEPROC terminatePtr; + + // 1.1 + PFNEGLBINDTEXIMAGEPROC bindTexImagePtr; + PFNEGLRELEASETEXIMAGEPROC releaseTexImagePtr; + PFNEGLSWAPINTERVALPROC swapIntervalPtr; + + // EGL_KHR_image + PFNEGLCREATEIMAGEKHRPROC createImageKHRPtr; + PFNEGLDESTROYIMAGEKHRPROC destroyImageKHRPtr; + + // EGL_KHR_fence_sync + PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSyncKHRPtr; + PFNEGLCREATESYNCKHRPROC createSyncKHRPtr; + PFNEGLDESTROYSYNCKHRPROC destroySyncKHRPtr; + PFNEGLGETSYNCATTRIBKHRPROC getSyncAttribKHRPtr; +}; + +FunctionsEGL::FunctionsEGL() + : majorVersion(0), minorVersion(0), mFnPtrs(new EGLDispatchTable()), mEGLDisplay(EGL_NO_DISPLAY) +{ +} + +FunctionsEGL::~FunctionsEGL() +{ + SafeDelete(mFnPtrs); +} + +egl::Error FunctionsEGL::initialize(EGLNativeDisplayType nativeDisplay) +{ +#define ANGLE_GET_PROC_OR_ERROR(MEMBER, NAME) \ + if (!SetPtr(MEMBER, getProcAddress(#NAME))) \ + { \ + return egl::Error(EGL_NOT_INITIALIZED, "Could not load EGL entry point " #NAME); \ + } + + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindAPIPtr, eglBindAPI); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->chooseConfigPtr, eglChooseConfig); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createContextPtr, eglCreateContext); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createPbufferSurfacePtr, eglCreatePbufferSurface); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createWindowSurfacePtr, eglCreateWindowSurface); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyContextPtr, eglDestroyContext); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySurfacePtr, eglDestroySurface); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getConfigAttribPtr, eglGetConfigAttrib); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getDisplayPtr, eglGetDisplay); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getErrorPtr, eglGetError); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->initializePtr, eglInitialize); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->makeCurrentPtr, eglMakeCurrent); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->queryStringPtr, eglQueryString); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->querySurfacePtr, eglQuerySurface); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapBuffersPtr, eglSwapBuffers); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->terminatePtr, eglTerminate); + + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindTexImagePtr, eglBindTexImage); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->releaseTexImagePtr, eglReleaseTexImage); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalPtr, eglSwapInterval); + + mEGLDisplay = mFnPtrs->getDisplayPtr(nativeDisplay); + if (mEGLDisplay == EGL_NO_DISPLAY) + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to get system egl display"); + } + if (mFnPtrs->initializePtr(mEGLDisplay, &majorVersion, &minorVersion) != EGL_TRUE) + { + return egl::Error(mFnPtrs->getErrorPtr(), "Failed to initialize system egl"); + } + if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 4)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Unsupported EGL version (require at least 1.4)."); + } + if (mFnPtrs->bindAPIPtr(EGL_OPENGL_ES_API) != EGL_TRUE) + { + return egl::Error(mFnPtrs->getErrorPtr(), "Failed to bind API in system egl"); + } + + const char *extensions = queryString(EGL_EXTENSIONS); + if (!extensions) + { + return egl::Error(mFnPtrs->getErrorPtr(), "Faild to query extensions in system egl"); + } + angle::SplitStringAlongWhitespace(extensions, &mExtensions); + + if (hasExtension("EGL_KHR_image_base")) + { + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createImageKHRPtr, eglCreateImageKHR); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyImageKHRPtr, eglDestroyImageKHR); + } + if (hasExtension("EGL_KHR_fence_sync")) + { + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->clientWaitSyncKHRPtr, eglClientWaitSyncKHR); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createSyncKHRPtr, eglCreateSyncKHR); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySyncKHRPtr, eglDestroySyncKHR); + ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getSyncAttribKHRPtr, eglGetSyncAttribKHR); + } + +#undef ANGLE_GET_PROC_OR_ERROR + + return egl::Error(EGL_SUCCESS); +} + +egl::Error FunctionsEGL::terminate() +{ + if (mFnPtrs->terminatePtr(mEGLDisplay) == EGL_TRUE) + { + mEGLDisplay = nullptr; + return egl::Error(EGL_SUCCESS); + } + return egl::Error(mFnPtrs->getErrorPtr()); +} + +class FunctionsGLEGL : public FunctionsGL +{ + public: + FunctionsGLEGL(const FunctionsEGL &egl) : mEGL(egl) {} + + ~FunctionsGLEGL() override {} + + private: + void *loadProcAddress(const std::string &function) override + { + return mEGL.getProcAddress(function.c_str()); + } + + const FunctionsEGL &mEGL; +}; + +FunctionsGL *FunctionsEGL::makeFunctionsGL(void) const +{ + return new FunctionsGLEGL(*this); +} + +bool FunctionsEGL::hasExtension(const char *extension) const +{ + return std::find(mExtensions.begin(), mExtensions.end(), extension) != mExtensions.end(); +} + +EGLDisplay FunctionsEGL::getDisplay() const +{ + return mEGLDisplay; +} + +EGLint FunctionsEGL::getError() const +{ + return mFnPtrs->getErrorPtr(); +} + +EGLBoolean FunctionsEGL::chooseConfig(EGLint const *attribList, + EGLConfig *configs, + EGLint configSize, + EGLint *numConfig) const +{ + return mFnPtrs->chooseConfigPtr(mEGLDisplay, attribList, configs, configSize, numConfig); +} + +EGLBoolean FunctionsEGL::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) const +{ + return mFnPtrs->getConfigAttribPtr(mEGLDisplay, config, attribute, value); +} + +EGLContext FunctionsEGL::createContext(EGLConfig config, + EGLContext share_context, + EGLint const *attrib_list) const +{ + return mFnPtrs->createContextPtr(mEGLDisplay, config, share_context, attrib_list); +} + +EGLSurface FunctionsEGL::createPbufferSurface(EGLConfig config, const EGLint *attrib_list) const +{ + return mFnPtrs->createPbufferSurfacePtr(mEGLDisplay, config, attrib_list); +} + +EGLSurface FunctionsEGL::createWindowSurface(EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list) const +{ + return mFnPtrs->createWindowSurfacePtr(mEGLDisplay, config, win, attrib_list); +} + +EGLBoolean FunctionsEGL::destroyContext(EGLContext context) const +{ + return mFnPtrs->destroyContextPtr(mEGLDisplay, context); +} + +EGLBoolean FunctionsEGL::destroySurface(EGLSurface surface) const +{ + return mFnPtrs->destroySurfacePtr(mEGLDisplay, surface); +} + +EGLBoolean FunctionsEGL::makeCurrent(EGLSurface surface, EGLContext context) const +{ + return mFnPtrs->makeCurrentPtr(mEGLDisplay, surface, surface, context); +} + +char const *FunctionsEGL::queryString(EGLint name) const +{ + return mFnPtrs->queryStringPtr(mEGLDisplay, name); +} + +EGLBoolean FunctionsEGL::querySurface(EGLSurface surface, EGLint attribute, EGLint *value) const +{ + return mFnPtrs->querySurfacePtr(mEGLDisplay, surface, attribute, value); +} + +EGLBoolean FunctionsEGL::swapBuffers(EGLSurface surface) const +{ + return mFnPtrs->swapBuffersPtr(mEGLDisplay, surface); +} + +EGLBoolean FunctionsEGL::bindTexImage(EGLSurface surface, EGLint buffer) const +{ + return mFnPtrs->bindTexImagePtr(mEGLDisplay, surface, buffer); +} + +EGLBoolean FunctionsEGL::releaseTexImage(EGLSurface surface, EGLint buffer) const +{ + return mFnPtrs->releaseTexImagePtr(mEGLDisplay, surface, buffer); +} + +EGLBoolean FunctionsEGL::swapInterval(EGLint interval) const +{ + return mFnPtrs->swapIntervalPtr(mEGLDisplay, interval); +} + +EGLImageKHR FunctionsEGL::createImageKHR(EGLContext context, + EGLenum target, + EGLClientBuffer buffer, + const EGLint *attrib_list) const +{ + return mFnPtrs->createImageKHRPtr(mEGLDisplay, context, target, buffer, attrib_list); +} + +EGLBoolean FunctionsEGL::destroyImageKHR(EGLImageKHR image) const +{ + return mFnPtrs->destroyImageKHRPtr(mEGLDisplay, image); +} + +EGLSyncKHR FunctionsEGL::createSyncKHR(EGLenum type, const EGLint *attrib_list) +{ + return mFnPtrs->createSyncKHRPtr(mEGLDisplay, type, attrib_list); +} + +EGLBoolean FunctionsEGL::destroySyncKHR(EGLSyncKHR sync) +{ + return mFnPtrs->destroySyncKHRPtr(mEGLDisplay, sync); +} + +EGLint FunctionsEGL::clientWaitSyncKHR(EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) +{ + return mFnPtrs->clientWaitSyncKHRPtr(mEGLDisplay, sync, flags, timeout); +} + +EGLBoolean FunctionsEGL::getSyncAttribKHR(EGLSyncKHR sync, EGLint attribute, EGLint *value) +{ + return mFnPtrs->getSyncAttribKHRPtr(mEGLDisplay, sync, attribute, value); +} +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.h b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.h new file mode 100755 index 000000000..43d5622e6 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 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. +// + +// FunctionsEGL.h: Defines the FunctionsEGL class to load functions and data from EGL + +#ifndef LIBANGLE_RENDERER_GL_CROS_FUNCTIONSEGL_H_ +#define LIBANGLE_RENDERER_GL_CROS_FUNCTIONSEGL_H_ + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <string> +#include <vector> + +#include "libANGLE/Error.h" + +namespace rx +{ + +class FunctionsGL; + +class FunctionsEGL +{ + public: + FunctionsEGL(); + virtual ~FunctionsEGL(); + + int majorVersion; + int minorVersion; + + egl::Error initialize(EGLNativeDisplayType nativeDisplay); + egl::Error terminate(); + + virtual void *getProcAddress(const char *name) const = 0; + + FunctionsGL *makeFunctionsGL() const; + bool hasExtension(const char *extension) const; + EGLDisplay getDisplay() const; + EGLint getError() const; + + EGLBoolean chooseConfig(EGLint const *attrib_list, + EGLConfig *configs, + EGLint config_size, + EGLint *num_config) const; + EGLBoolean getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) const; + EGLContext createContext(EGLConfig config, + EGLContext share_context, + EGLint const *attrib_list) const; + EGLSurface createPbufferSurface(EGLConfig config, const EGLint *attrib_list) const; + EGLSurface createWindowSurface(EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list) const; + EGLBoolean destroyContext(EGLContext context) const; + EGLBoolean destroySurface(EGLSurface surface) const; + EGLBoolean makeCurrent(EGLSurface surface, EGLContext context) const; + const char *queryString(EGLint name) const; + EGLBoolean querySurface(EGLSurface surface, EGLint attribute, EGLint *value) const; + EGLBoolean swapBuffers(EGLSurface surface) const; + + EGLBoolean bindTexImage(EGLSurface surface, EGLint buffer) const; + EGLBoolean releaseTexImage(EGLSurface surface, EGLint buffer) const; + EGLBoolean swapInterval(EGLint interval) const; + + EGLImageKHR createImageKHR(EGLContext context, + EGLenum target, + EGLClientBuffer buffer, + const EGLint *attrib_list) const; + EGLBoolean destroyImageKHR(EGLImageKHR image) const; + + EGLSyncKHR createSyncKHR(EGLenum type, const EGLint *attrib_list); + EGLBoolean destroySyncKHR(EGLSyncKHR sync); + EGLint clientWaitSyncKHR(EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); + EGLBoolean getSyncAttribKHR(EGLSyncKHR sync, EGLint attribute, EGLint *value); + + private: + // So as to isolate from angle we do not include angleutils.h and cannot + // use angle::NonCopyable so we replicated it here instead. + FunctionsEGL(const FunctionsEGL &) = delete; + void operator=(const FunctionsEGL &) = delete; + + struct EGLDispatchTable; + EGLDispatchTable *mFnPtrs; + EGLDisplay mEGLDisplay; + std::vector<std::string> mExtensions; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_CROS_FUNCTIONSEGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGLDL.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGLDL.cpp new file mode 100755 index 000000000..e6ef45d8d --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGLDL.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 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. +// + +// FunctionsEGLDL.cpp: Implements the FunctionsEGLDL class. + +#include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h" + +#include <dlfcn.h> + +namespace rx +{ + +DynamicLib::DynamicLib() : handle(nullptr) +{ +} + +DynamicLib::~DynamicLib() +{ + if (handle) + { + dlclose(handle); + handle = nullptr; + } +} + +// Due to a bug in Mesa (or maybe libdl) it's not possible to close and re-open libEGL.so +// an arbitrary number of times. End2end tests would die after a couple hundred tests. +// So we use a static object with a destructor to close the library when the program exits. +// TODO(fjhenigman) File a bug and put a link here. +DynamicLib FunctionsEGLDL::sNativeLib; + +FunctionsEGLDL::FunctionsEGLDL() : mGetProcAddressPtr(nullptr) +{ +} + +FunctionsEGLDL::~FunctionsEGLDL() +{ +} + +egl::Error FunctionsEGLDL::initialize(EGLNativeDisplayType nativeDisplay, const char *libName) +{ + if (!sNativeLib.handle) + { + sNativeLib.handle = dlopen(libName, RTLD_NOW); + if (!sNativeLib.handle) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not dlopen native EGL: %s", dlerror()); + } + } + + mGetProcAddressPtr = + reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(dlsym(sNativeLib.handle, "eglGetProcAddress")); + if (!mGetProcAddressPtr) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not find eglGetProcAddress"); + } + + return FunctionsEGL::initialize(nativeDisplay); +} + +void *FunctionsEGLDL::getProcAddress(const char *name) const +{ + void *f = reinterpret_cast<void *>(mGetProcAddressPtr(name)); + if (f) + { + return f; + } + return dlsym(sNativeLib.handle, name); +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGLDL.h b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGLDL.h new file mode 100755 index 000000000..d69df77ab --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/FunctionsEGLDL.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 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. +// + +// FunctionsEGL.h: Implements FunctionsEGL with dlopen/dlsym/dlclose + +#ifndef LIBANGLE_RENDERER_GL_CROS_FUNCTIONSEGLDL_H_ +#define LIBANGLE_RENDERER_GL_CROS_FUNCTIONSEGLDL_H_ + +#include "libANGLE/renderer/gl/egl/FunctionsEGL.h" +#include "libANGLE/renderer/gl/egl/functionsegl_typedefs.h" + +namespace rx +{ + +class DynamicLib final +{ + public: + void *handle; + + DynamicLib(); + ~DynamicLib(); +}; + +class FunctionsEGLDL : public FunctionsEGL +{ + public: + FunctionsEGLDL(); + ~FunctionsEGLDL() override; + + egl::Error initialize(EGLNativeDisplayType nativeDisplay, const char *libName); + void *getProcAddress(const char *name) const override; + + private: + PFNEGLGETPROCADDRESSPROC mGetProcAddressPtr; + static DynamicLib sNativeLib; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_CROS_FUNCTIONSEGLDL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/PbufferSurfaceEGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/PbufferSurfaceEGL.cpp new file mode 100755 index 000000000..68da9f2b8 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/PbufferSurfaceEGL.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 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. +// + +// PbufferSurfaceEGL.h: EGL implementation of egl::Surface for pbuffers + +#include "libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h" + +namespace rx +{ + +PbufferSurfaceEGL::PbufferSurfaceEGL(const egl::SurfaceState &state, + const FunctionsEGL *egl, + EGLConfig config, + const std::vector<EGLint> &attribList, + EGLContext context, + RendererGL *renderer) + : SurfaceEGL(state, egl, config, attribList, context, renderer) +{ +} + +PbufferSurfaceEGL::~PbufferSurfaceEGL() +{ +} + +egl::Error PbufferSurfaceEGL::initialize() +{ + mSurface = mEGL->createPbufferSurface(mConfig, mAttribList.data()); + if (mSurface == EGL_NO_SURFACE) + { + return egl::Error(mEGL->getError(), "eglCreatePbufferSurface failed"); + } + + return egl::Error(EGL_SUCCESS); +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h b/gfx/angle/src/libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h new file mode 100755 index 000000000..ff557f2ca --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 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. +// + +// PbufferSurfaceEGL.h: EGL implementation of egl::Surface for pbuffers + +#ifndef LIBANGLE_RENDERER_GL_EGL_PBUFFERSURFACEEGL_H_ +#define LIBANGLE_RENDERER_GL_EGL_PBUFFERSURFACEEGL_H_ + +#include <vector> +#include <EGL/egl.h> + +#include "libANGLE/renderer/gl/egl/SurfaceEGL.h" + +namespace rx +{ + +class PbufferSurfaceEGL : public SurfaceEGL +{ + public: + PbufferSurfaceEGL(const egl::SurfaceState &state, + const FunctionsEGL *egl, + EGLConfig config, + const std::vector<EGLint> &attribList, + EGLContext context, + RendererGL *renderer); + ~PbufferSurfaceEGL() override; + + egl::Error initialize() override; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_PBUFFERSURFACEEGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/SurfaceEGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/SurfaceEGL.cpp new file mode 100755 index 000000000..693b61c9c --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/SurfaceEGL.cpp @@ -0,0 +1,132 @@ +// +// Copyright (c) 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, + const std::vector<EGLint> &attribList, + EGLContext context, + RendererGL *renderer) + : SurfaceGL(state, renderer), + mEGL(egl), + mConfig(config), + mAttribList(attribList), + mSurface(EGL_NO_SURFACE), + mContext(context) +{ +} + +SurfaceEGL::~SurfaceEGL() +{ + if (mSurface != EGL_NO_SURFACE) + { + EGLBoolean success = mEGL->destroySurface(mSurface); + ASSERT(success == EGL_TRUE); + } +} + +egl::Error SurfaceEGL::makeCurrent() +{ + EGLBoolean success = mEGL->makeCurrent(mSurface, mContext); + if (success == EGL_FALSE) + { + return egl::Error(mEGL->getError(), "eglMakeCurrent failed"); + } + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceEGL::swap() +{ + EGLBoolean success = mEGL->swapBuffers(mSurface); + if (success == EGL_FALSE) + { + return egl::Error(mEGL->getError(), "eglSwapBuffers failed"); + } + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceEGL::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_BAD_SURFACE); +} + +egl::Error SurfaceEGL::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_BAD_SURFACE); +} + +egl::Error SurfaceEGL::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + EGLBoolean success = mEGL->bindTexImage(mSurface, buffer); + if (success == EGL_FALSE) + { + return egl::Error(mEGL->getError(), "eglBindTexImage failed"); + } + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceEGL::releaseTexImage(EGLint buffer) +{ + EGLBoolean success = mEGL->releaseTexImage(mSurface, buffer); + if (success == EGL_FALSE) + { + return egl::Error(mEGL->getError(), "eglReleaseTexImage failed"); + } + return egl::Error(EGL_SUCCESS); +} + +void SurfaceEGL::setSwapInterval(EGLint interval) +{ + EGLBoolean success = mEGL->swapInterval(interval); + if (success == EGL_FALSE) + { + ERR("eglSwapInterval error 0x%04x", 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; +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/SurfaceEGL.h b/gfx/angle/src/libANGLE/renderer/gl/egl/SurfaceEGL.h new file mode 100755 index 000000000..ee1568c9e --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/SurfaceEGL.h @@ -0,0 +1,55 @@ +// +// Copyright (c) 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.h: common interface for EGL surfaces + +#ifndef LIBANGLE_RENDERER_GL_EGL_SURFACEEGL_H_ +#define LIBANGLE_RENDERER_GL_EGL_SURFACEEGL_H_ + +#include <EGL/egl.h> + +#include "libANGLE/renderer/gl/SurfaceGL.h" +#include "libANGLE/renderer/gl/egl/FunctionsEGL.h" + +namespace rx +{ + +class SurfaceEGL : public SurfaceGL +{ + public: + SurfaceEGL(const egl::SurfaceState &state, + const FunctionsEGL *egl, + EGLConfig config, + const std::vector<EGLint> &attribList, + EGLContext context, + RendererGL *renderer); + ~SurfaceEGL() override; + + egl::Error makeCurrent() override; + egl::Error swap() override; + egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; + egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override; + egl::Error releaseTexImage(EGLint buffer) override; + void setSwapInterval(EGLint interval) override; + EGLint getWidth() const override; + EGLint getHeight() const override; + EGLint isPostSubBufferSupported() const override; + EGLint getSwapBehavior() const override; + + protected: + const FunctionsEGL *mEGL; + EGLConfig mConfig; + std::vector<EGLint> mAttribList; + EGLSurface mSurface; + + private: + EGLContext mContext; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_SURFACEEGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/WindowSurfaceEGL.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/WindowSurfaceEGL.cpp new file mode 100755 index 000000000..db226ee18 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/WindowSurfaceEGL.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 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. +// + +// WindowSurfaceEGL.h: EGL implementation of egl::Surface for windows + +#include "libANGLE/renderer/gl/egl/WindowSurfaceEGL.h" + +namespace rx +{ + +WindowSurfaceEGL::WindowSurfaceEGL(const egl::SurfaceState &state, + const FunctionsEGL *egl, + EGLConfig config, + EGLNativeWindowType window, + const std::vector<EGLint> &attribList, + EGLContext context, + RendererGL *renderer) + : SurfaceEGL(state, egl, config, attribList, context, renderer), mWindow(window) +{ +} + +WindowSurfaceEGL::~WindowSurfaceEGL() +{ +} + +egl::Error WindowSurfaceEGL::initialize() +{ + mSurface = mEGL->createWindowSurface(mConfig, mWindow, mAttribList.data()); + if (mSurface == EGL_NO_SURFACE) + { + return egl::Error(mEGL->getError(), "eglCreateWindowSurface failed"); + } + + return egl::Error(EGL_SUCCESS); +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/WindowSurfaceEGL.h b/gfx/angle/src/libANGLE/renderer/gl/egl/WindowSurfaceEGL.h new file mode 100755 index 000000000..f9da4c27c --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/WindowSurfaceEGL.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 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. +// + +// WindowSurfaceEGL.h: EGL implementation of egl::Surface for windows + +#ifndef LIBANGLE_RENDERER_GL_EGL_WINDOWSURFACEEGL_H_ +#define LIBANGLE_RENDERER_GL_EGL_WINDOWSURFACEEGL_H_ + +#include "libANGLE/renderer/gl/egl/SurfaceEGL.h" + +namespace rx +{ + +class WindowSurfaceEGL : public SurfaceEGL +{ + public: + WindowSurfaceEGL(const egl::SurfaceState &state, + const FunctionsEGL *egl, + EGLConfig config, + EGLNativeWindowType window, + const std::vector<EGLint> &attribList, + EGLContext context, + RendererGL *renderer); + ~WindowSurfaceEGL() override; + + egl::Error initialize() override; + + private: + EGLNativeWindowType mWindow; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_WINDOWSURFACEEGL_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp new file mode 100755 index 000000000..b689578c9 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp @@ -0,0 +1,385 @@ +// +// Copyright (c) 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. +// + +// DisplayAndroid.cpp: Android implementation of egl::Display + +#include <android/native_window.h> + +#include "common/debug.h" +#include "libANGLE/Display.h" +#include "libANGLE/renderer/gl/renderergl_utils.h" +#include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h" +#include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h" +#include "libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h" +#include "libANGLE/renderer/gl/egl/WindowSurfaceEGL.h" + +namespace +{ +const char *GetEGLPath() +{ +#if defined(__LP64__) + return "/system/lib64/libEGL.so"; +#else + return "/system/lib/libEGL.so"; +#endif +} +} // namespace + +namespace rx +{ + +DisplayAndroid::DisplayAndroid() : DisplayEGL(), mDummyPbuffer(EGL_NO_SURFACE) +{ +} + +DisplayAndroid::~DisplayAndroid() +{ +} + +egl::Error DisplayAndroid::initialize(egl::Display *display) +{ + FunctionsEGLDL *egl = new FunctionsEGLDL(); + mEGL = egl; + ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), GetEGLPath())); + + gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion); + ASSERT(eglVersion >= gl::Version(1, 4)); + + static_assert(EGL_OPENGL_ES3_BIT == EGL_OPENGL_ES3_BIT_KHR, "Extension define must match core"); + EGLint esBit = (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context")) + ? EGL_OPENGL_ES3_BIT + : EGL_OPENGL_ES2_BIT; + + // clang-format off + mConfigAttribList = + { + // Choose RGBA8888 + EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + // EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths + // must match for contexts to be compatible. + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_SAMPLE_BUFFERS, 0, + // Android doesn't support pixmaps + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_CONFORMANT, esBit, + EGL_RENDERABLE_TYPE, esBit, + EGL_NONE + }; + // clang-format on + EGLint numConfig; + + EGLBoolean success = mEGL->chooseConfig(mConfigAttribList.data(), &mConfig, 1, &numConfig); + if (success == EGL_FALSE) + { + return egl::Error(mEGL->getError(), "eglChooseConfig failed"); + } + + ANGLE_TRY(initializeContext(display->getAttributeMap())); + + int dummyPbufferAttribs[] = { + EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, + }; + mDummyPbuffer = mEGL->createPbufferSurface(mConfig, dummyPbufferAttribs); + if (mDummyPbuffer == EGL_NO_SURFACE) + { + return egl::Error(mEGL->getError(), "eglCreatePbufferSurface failed"); + } + + success = mEGL->makeCurrent(mDummyPbuffer, mContext); + if (success == EGL_FALSE) + { + return egl::Error(mEGL->getError(), "eglMakeCurrent failed"); + } + + mFunctionsGL = mEGL->makeFunctionsGL(); + mFunctionsGL->initialize(); + + return DisplayGL::initialize(display); +} + +void DisplayAndroid::terminate() +{ + DisplayGL::terminate(); + + EGLBoolean success = mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (success == EGL_FALSE) + { + ERR("eglMakeCurrent error 0x%04x", mEGL->getError()); + } + + if (mDummyPbuffer != EGL_NO_SURFACE) + { + success = mEGL->destroySurface(mDummyPbuffer); + mDummyPbuffer = EGL_NO_SURFACE; + if (success == EGL_FALSE) + { + ERR("eglDestroySurface error 0x%04x", mEGL->getError()); + } + } + + if (mContext != EGL_NO_CONTEXT) + { + success = mEGL->destroyContext(mContext); + mContext = EGL_NO_CONTEXT; + if (success == EGL_FALSE) + { + ERR("eglDestroyContext error 0x%04x", mEGL->getError()); + } + } + + egl::Error result = mEGL->terminate(); + if (result.isError()) + { + ERR("eglTerminate error 0x%04x", result.getCode()); + } + + SafeDelete(mEGL); + SafeDelete(mFunctionsGL); +} + +SurfaceImpl *DisplayAndroid::createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) +{ + EGLConfig config; + EGLint numConfig; + EGLBoolean success; + + const EGLint configAttribList[] = {EGL_CONFIG_ID, mConfigIds[configuration->configID], + EGL_NONE}; + success = mEGL->chooseConfig(configAttribList, &config, 1, &numConfig); + ASSERT(success && numConfig == 1); + + return new WindowSurfaceEGL(state, mEGL, config, window, attribs.toIntVector(), mContext, + getRenderer()); +} + +SurfaceImpl *DisplayAndroid::createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) +{ + EGLConfig config; + EGLint numConfig; + EGLBoolean success; + + const EGLint configAttribList[] = {EGL_CONFIG_ID, mConfigIds[configuration->configID], + EGL_NONE}; + success = mEGL->chooseConfig(configAttribList, &config, 1, &numConfig); + ASSERT(success && numConfig == 1); + + return new PbufferSurfaceEGL(state, mEGL, config, attribs.toIntVector(), mContext, + getRenderer()); +} + +SurfaceImpl *DisplayAndroid::createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +SurfaceImpl *DisplayAndroid::createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +ImageImpl *DisplayAndroid::createImage(EGLenum target, + egl::ImageSibling *buffer, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return DisplayGL::createImage(target, buffer, attribs); +} + +template <typename T> +void DisplayAndroid::getConfigAttrib(EGLConfig config, EGLint attribute, T *value) const +{ + EGLint tmp; + EGLBoolean success = mEGL->getConfigAttrib(config, attribute, &tmp); + ASSERT(success == EGL_TRUE); + *value = tmp; +} + +egl::ConfigSet DisplayAndroid::generateConfigs() +{ + egl::ConfigSet configSet; + mConfigIds.clear(); + + EGLint numConfigs; + EGLBoolean success = mEGL->chooseConfig(mConfigAttribList.data(), nullptr, 0, &numConfigs); + ASSERT(success == EGL_TRUE && numConfigs > 0); + + std::vector<EGLConfig> configs(numConfigs); + EGLint numConfigs2; + success = + mEGL->chooseConfig(mConfigAttribList.data(), configs.data(), numConfigs, &numConfigs2); + ASSERT(success == EGL_TRUE && numConfigs2 == numConfigs); + + for (int i = 0; i < numConfigs; i++) + { + egl::Config config; + + getConfigAttrib(configs[i], EGL_BUFFER_SIZE, &config.bufferSize); + getConfigAttrib(configs[i], EGL_RED_SIZE, &config.redSize); + getConfigAttrib(configs[i], EGL_GREEN_SIZE, &config.greenSize); + getConfigAttrib(configs[i], EGL_BLUE_SIZE, &config.blueSize); + getConfigAttrib(configs[i], EGL_LUMINANCE_SIZE, &config.luminanceSize); + getConfigAttrib(configs[i], EGL_ALPHA_SIZE, &config.alphaSize); + getConfigAttrib(configs[i], EGL_ALPHA_MASK_SIZE, &config.alphaMaskSize); + getConfigAttrib(configs[i], EGL_BIND_TO_TEXTURE_RGB, &config.bindToTextureRGB); + getConfigAttrib(configs[i], EGL_BIND_TO_TEXTURE_RGBA, &config.bindToTextureRGBA); + getConfigAttrib(configs[i], EGL_COLOR_BUFFER_TYPE, &config.colorBufferType); + getConfigAttrib(configs[i], EGL_CONFIG_CAVEAT, &config.configCaveat); + getConfigAttrib(configs[i], EGL_CONFIG_ID, &config.configID); + getConfigAttrib(configs[i], EGL_CONFORMANT, &config.conformant); + getConfigAttrib(configs[i], EGL_DEPTH_SIZE, &config.depthSize); + getConfigAttrib(configs[i], EGL_LEVEL, &config.level); + getConfigAttrib(configs[i], EGL_MAX_PBUFFER_WIDTH, &config.maxPBufferWidth); + getConfigAttrib(configs[i], EGL_MAX_PBUFFER_HEIGHT, &config.maxPBufferHeight); + getConfigAttrib(configs[i], EGL_MAX_PBUFFER_PIXELS, &config.maxPBufferPixels); + getConfigAttrib(configs[i], EGL_MAX_SWAP_INTERVAL, &config.maxSwapInterval); + getConfigAttrib(configs[i], EGL_MIN_SWAP_INTERVAL, &config.minSwapInterval); + getConfigAttrib(configs[i], EGL_NATIVE_RENDERABLE, &config.nativeRenderable); + getConfigAttrib(configs[i], EGL_NATIVE_VISUAL_ID, &config.nativeVisualID); + getConfigAttrib(configs[i], EGL_NATIVE_VISUAL_TYPE, &config.nativeVisualType); + getConfigAttrib(configs[i], EGL_RENDERABLE_TYPE, &config.renderableType); + getConfigAttrib(configs[i], EGL_SAMPLE_BUFFERS, &config.sampleBuffers); + getConfigAttrib(configs[i], EGL_SAMPLES, &config.samples); + getConfigAttrib(configs[i], EGL_STENCIL_SIZE, &config.stencilSize); + getConfigAttrib(configs[i], EGL_SURFACE_TYPE, &config.surfaceType); + getConfigAttrib(configs[i], EGL_TRANSPARENT_TYPE, &config.transparentType); + getConfigAttrib(configs[i], EGL_TRANSPARENT_RED_VALUE, &config.transparentRedValue); + getConfigAttrib(configs[i], EGL_TRANSPARENT_GREEN_VALUE, &config.transparentGreenValue); + getConfigAttrib(configs[i], EGL_TRANSPARENT_BLUE_VALUE, &config.transparentBlueValue); + + if (config.colorBufferType == EGL_RGB_BUFFER) + { + if (config.redSize == 8 && config.greenSize == 8 && config.blueSize == 8 && + config.alphaSize == 8) + { + config.renderTargetFormat = GL_RGBA8; + } + else if (config.redSize == 8 && config.greenSize == 8 && config.blueSize == 8 && + config.alphaSize == 0) + { + config.renderTargetFormat = GL_RGB8; + } + else if (config.redSize == 5 && config.greenSize == 6 && config.blueSize == 5 && + config.alphaSize == 0) + { + config.renderTargetFormat = GL_RGB565; + } + else + { + UNREACHABLE(); + } + } + else + { + UNREACHABLE(); + } + + if (config.depthSize == 0 && config.stencilSize == 0) + { + config.depthStencilFormat = GL_ZERO; + } + else if (config.depthSize == 16 && config.stencilSize == 0) + { + config.depthStencilFormat = GL_DEPTH_COMPONENT16; + } + else if (config.depthSize == 24 && config.stencilSize == 0) + { + config.depthStencilFormat = GL_DEPTH_COMPONENT24; + } + else if (config.depthSize == 24 && config.stencilSize == 8) + { + config.depthStencilFormat = GL_DEPTH24_STENCIL8; + } + else if (config.depthSize == 0 && config.stencilSize == 8) + { + config.depthStencilFormat = GL_STENCIL_INDEX8; + } + else + { + UNREACHABLE(); + } + + config.matchNativePixmap = EGL_NONE; + config.optimalOrientation = 0; + + int internalId = configSet.add(config); + mConfigIds[internalId] = config.configID; + } + + return configSet; +} + +bool DisplayAndroid::testDeviceLost() +{ + return false; +} + +egl::Error DisplayAndroid::restoreLostDevice() +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const +{ + return ANativeWindow_getFormat(window) >= 0; +} + +egl::Error DisplayAndroid::getDevice(DeviceImpl **device) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayAndroid::waitClient() const +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayAndroid::waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayAndroid::getDriverVersion(std::string *version) const +{ + VendorID vendor = GetVendorID(mFunctionsGL); + + switch (vendor) + { + case VENDOR_ID_QUALCOMM: + *version = reinterpret_cast<const char *>(mFunctionsGL->getString(GL_VERSION)); + return egl::Error(EGL_SUCCESS); + default: + *version = ""; + return egl::Error(EGL_SUCCESS); + } +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h b/gfx/angle/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h new file mode 100755 index 000000000..0be9bb465 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h @@ -0,0 +1,78 @@ +// +// Copyright (c) 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. +// + +// DisplayAndroid.h: Android implementation of egl::Display + +#ifndef LIBANGLE_RENDERER_GL_EGL_ANDROID_DISPLAYANDROID_H_ +#define LIBANGLE_RENDERER_GL_EGL_ANDROID_DISPLAYANDROID_H_ + +#include <map> +#include <string> +#include <vector> + +#include "libANGLE/renderer/gl/egl/DisplayEGL.h" + +namespace rx +{ + +class DisplayAndroid : public DisplayEGL +{ + public: + DisplayAndroid(); + ~DisplayAndroid() override; + + egl::Error initialize(egl::Display *display) override; + void terminate() override; + + SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) override; + + ImageImpl *createImage(EGLenum target, + egl::ImageSibling *buffer, + const egl::AttributeMap &attribs) override; + + egl::ConfigSet generateConfigs() override; + + bool testDeviceLost() override; + egl::Error restoreLostDevice() override; + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + + egl::Error getDevice(DeviceImpl **device) override; + + egl::Error waitClient() const override; + egl::Error waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const override; + + egl::Error getDriverVersion(std::string *version) const override; + + private: + template <typename T> + void getConfigAttrib(EGLConfig config, EGLint attribute, T *value) const; + + std::vector<EGLint> mConfigAttribList; + std::map<EGLint, EGLint> mConfigIds; + EGLSurface mDummyPbuffer; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_ANDROID_DISPLAYANDROID_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/functionsegl_typedefs.h b/gfx/angle/src/libANGLE/renderer/gl/egl/functionsegl_typedefs.h new file mode 100755 index 000000000..78f9009bf --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/functionsegl_typedefs.h @@ -0,0 +1,131 @@ +// +// Copyright (c) 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. +// + +// functionsegl_typedefs.h: Typedefs of EGL functions. + +#ifndef LIBANGLE_RENDERER_GL_EGL_FUNCTIONSEGLTYPEDEFS_H_ +#define LIBANGLE_RENDERER_GL_EGL_FUNCTIONSEGLTYPEDEFS_H_ + +#include <EGL/egl.h> + +namespace rx +{ +// EGL 1.0 +typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, + const EGLint *attrib_list, + EGLConfig *configs, + EGLint config_size, + EGLint *num_config); +typedef EGLBoolean (*PFNEGLCOPYBUFFERSPROC)(EGLDisplay dpy, + EGLSurface surface, + EGLNativePixmapType target); +typedef EGLContext (*PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, + EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); +typedef EGLSurface (*PFNEGLCREATEPBUFFERSURFACEPROC)(EGLDisplay dpy, + EGLConfig config, + const EGLint *attrib_list); +typedef EGLSurface (*PFNEGLCREATEPIXMAPSURFACEPROC)(EGLDisplay dpy, + EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list); +typedef EGLSurface (*PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, + EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); +typedef EGLBoolean (*PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx); +typedef EGLBoolean (*PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean (*PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, + EGLConfig config, + EGLint attribute, + EGLint *value); +typedef EGLBoolean (*PFNEGLGETCONFIGSPROC)(EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, + EGLint *num_config); +typedef EGLDisplay (*PFNEGLGETCURRENTDISPLAYPROC)(void); +typedef EGLSurface (*PFNEGLGETCURRENTSURFACEPROC)(EGLint readdraw); +typedef EGLDisplay (*PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id); +typedef EGLint (*PFNEGLGETERRORPROC)(void); +typedef __eglMustCastToProperFunctionPointerType (*PFNEGLGETPROCADDRESSPROC)(const char *procname); +typedef EGLBoolean (*PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint *major, EGLint *minor); +typedef EGLBoolean (*PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, + EGLSurface draw, + EGLSurface read, + EGLContext ctx); +typedef EGLBoolean (*PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, + EGLContext ctx, + EGLint attribute, + EGLint *value); +typedef const char *(*PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name); +typedef EGLBoolean (*PFNEGLQUERYSURFACEPROC)(EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + EGLint *value); +typedef EGLBoolean (*PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean (*PFNEGLTERMINATEPROC)(EGLDisplay dpy); +typedef EGLBoolean (*PFNEGLWAITGLPROC)(void); +typedef EGLBoolean (*PFNEGLWAITNATIVEPROC)(EGLint engine); + +// EGL 1.1 +typedef EGLBoolean (*PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean (*PFNEGLRELEASETEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean (*PFNEGLSURFACEATTRIBPROC)(EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + EGLint value); +typedef EGLBoolean (*PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval); + +// EGL 1.2 +typedef EGLBoolean (*PFNEGLBINDAPIPROC)(EGLenum api); +typedef EGLenum (*PFNEGLQUERYAPIPROC)(void); +typedef EGLSurface (*PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC)(EGLDisplay dpy, + EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, + const EGLint *attrib_list); +typedef EGLBoolean (*PFNEGLRELEASETHREADPROC)(void); +typedef EGLBoolean (*PFNEGLWAITCLIENTPROC)(void); + +// EGL 1.3 + +// EGL 1.4 +typedef EGLContext (*PFNEGLGETCURRENTCONTEXTPROC)(void); + +// EGL 1.5 +typedef EGLSync (*PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list); +typedef EGLBoolean (*PFNEGLDESTROYSYNCPROC)(EGLDisplay dpy, EGLSync sync); +typedef EGLint (*PFNEGLCLIENTWAITSYNCPROC)(EGLDisplay dpy, + EGLSync sync, + EGLint flags, + EGLTime timeout); +typedef EGLBoolean (*PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, + EGLSync sync, + EGLint attribute, + EGLAttrib *value); +typedef EGLImage (*PFNEGLCREATEIMAGEPROC)(EGLDisplay dpy, + EGLContext ctx, + EGLenum target, + EGLClientBuffer buffer, + const EGLAttrib *attrib_list); +typedef EGLBoolean (*PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image); +typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list); +typedef EGLSurface (*PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, + EGLConfig config, + void *native_window, + const EGLAttrib *attrib_list); +typedef EGLSurface (*PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisplay dpy, + EGLConfig config, + void *native_pixmap, + const EGLAttrib *attrib_list); +typedef EGLBoolean (*PFNEGLWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags); + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_FUNCTIONSEGLTYPEDEFS_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp new file mode 100755 index 000000000..01549fcfa --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp @@ -0,0 +1,945 @@ +// +// Copyright (c) 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. +// + +// DisplayOzone.cpp: Ozone implementation of egl::Display + +#include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h" + +#include <fcntl.h> +#include <poll.h> +#include <iostream> +#include <unistd.h> +#include <sys/time.h> + +#include <EGL/eglext.h> + +#include <gbm.h> +#include <drm_fourcc.h> + +#include "common/debug.h" +#include "libANGLE/Config.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/gl/FramebufferGL.h" +#include "libANGLE/renderer/gl/RendererGL.h" +#include "libANGLE/renderer/gl/StateManagerGL.h" +#include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h" +#include "libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h" +#include "platform/Platform.h" + +// ARM-specific extension needed to make Mali GPU behave - not in any +// published header file. +#ifndef EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM +#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A +#endif + +#ifndef EGL_NO_CONFIG_MESA +#define EGL_NO_CONFIG_MESA ((EGLConfig)0) +#endif + +namespace +{ + +EGLint UnsignedToSigned(uint32_t u) +{ + return *reinterpret_cast<const EGLint *>(&u); +} + +drmModeModeInfoPtr ChooseMode(drmModeConnectorPtr conn) +{ + drmModeModeInfoPtr mode = nullptr; + ASSERT(conn); + ASSERT(conn->connection == DRM_MODE_CONNECTED); + // use first preferred mode if any, else end up with last mode in list + for (int i = 0; i < conn->count_modes; ++i) + { + mode = conn->modes + i; + if (mode->type & DRM_MODE_TYPE_PREFERRED) + { + break; + } + } + return mode; +} + +int ChooseCRTC(int fd, drmModeConnectorPtr conn) +{ + for (int i = 0; i < conn->count_encoders; ++i) + { + drmModeEncoderPtr enc = drmModeGetEncoder(fd, conn->encoders[i]); + unsigned long crtcs = enc->possible_crtcs; + drmModeFreeEncoder(enc); + if (crtcs) + { + return __builtin_ctzl(crtcs); + } + } + return -1; +} +} // namespace + +namespace rx +{ + +// TODO(fjhenigman) Implement swap control. Until then this is unused. +SwapControlData::SwapControlData() + : targetSwapInterval(0), maxSwapInterval(-1), currentSwapInterval(-1) +{ +} + +DisplayOzone::Buffer::Buffer(DisplayOzone *display, + uint32_t useFlags, + uint32_t gbmFormat, + uint32_t drmFormat, + uint32_t drmFormatFB, + int depthBits, + int stencilBits) + : mDisplay(display), + mNative(nullptr), + mWidth(0), + mHeight(0), + mDepthBits(depthBits), + mStencilBits(stencilBits), + mUseFlags(useFlags), + mGBMFormat(gbmFormat), + mDRMFormat(drmFormat), + mDRMFormatFB(drmFormatFB), + mBO(nullptr), + mDMABuf(-1), + mHasDRMFB(false), + mDRMFB(0), + mImage(EGL_NO_IMAGE_KHR), + mColorBuffer(0), + mDSBuffer(0), + mGLFB(0), + mTexture(0) +{ +} + +DisplayOzone::Buffer::~Buffer() +{ + mDisplay->mFunctionsGL->deleteFramebuffers(1, &mGLFB); + reset(); +} + +void DisplayOzone::Buffer::reset() +{ + if (mHasDRMFB) + { + int fd = gbm_device_get_fd(mDisplay->mGBM); + drmModeRmFB(fd, mDRMFB); + mHasDRMFB = false; + } + + FunctionsGL *gl = mDisplay->mFunctionsGL; + gl->deleteRenderbuffers(1, &mColorBuffer); + mColorBuffer = 0; + gl->deleteRenderbuffers(1, &mDSBuffer); + mDSBuffer = 0; + + // Here we might destroy the GL framebuffer (mGLFB) but unlike every other resource in Buffer, + // it does not get destroyed (and recreated) because when it is the default framebuffer for + // an ANGLE surface then ANGLE expects it to have the same lifetime as that surface. + + if (mImage != EGL_NO_IMAGE_KHR) + { + mDisplay->mEGL->destroyImageKHR(mImage); + mImage = EGL_NO_IMAGE_KHR; + } + + if (mTexture) + { + gl->deleteTextures(1, &mTexture); + mTexture = 0; + } + + if (mDMABuf >= 0) + { + close(mDMABuf); + mDMABuf = -1; + } + + if (mBO) + { + gbm_bo_destroy(mBO); + mBO = nullptr; + } +} + +bool DisplayOzone::Buffer::resize(int32_t width, int32_t height) +{ + if (mWidth == width && mHeight == height) + { + return true; + } + + reset(); + + if (width <= 0 || height <= 0) + { + return true; + } + + mBO = gbm_bo_create(mDisplay->mGBM, width, height, mGBMFormat, mUseFlags); + if (!mBO) + { + return false; + } + + mDMABuf = gbm_bo_get_fd(mBO); + if (mDMABuf < 0) + { + return false; + } + + // clang-format off + const EGLint attr[] = + { + EGL_WIDTH, width, + EGL_HEIGHT, height, + EGL_LINUX_DRM_FOURCC_EXT, UnsignedToSigned(mDRMFormat), + EGL_DMA_BUF_PLANE0_FD_EXT, mDMABuf, + EGL_DMA_BUF_PLANE0_PITCH_EXT, UnsignedToSigned(gbm_bo_get_stride(mBO)), + EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, + EGL_NONE, + }; + // clang-format on + + mImage = mDisplay->mEGL->createImageKHR(EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attr); + if (mImage == EGL_NO_IMAGE_KHR) + { + return false; + } + + FunctionsGL *gl = mDisplay->mFunctionsGL; + StateManagerGL *sm = mDisplay->getRenderer()->getStateManager(); + + gl->genRenderbuffers(1, &mColorBuffer); + sm->bindRenderbuffer(GL_RENDERBUFFER, mColorBuffer); + gl->eglImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mImage); + + sm->bindFramebuffer(GL_FRAMEBUFFER, mGLFB); + gl->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, + mColorBuffer); + + if (mDepthBits || mStencilBits) + { + gl->genRenderbuffers(1, &mDSBuffer); + sm->bindRenderbuffer(GL_RENDERBUFFER, mDSBuffer); + gl->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height); + } + + if (mDepthBits) + { + gl->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + mDSBuffer); + } + + if (mStencilBits) + { + gl->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + mDSBuffer); + } + + mWidth = width; + mHeight = height; + return true; +} + +bool DisplayOzone::Buffer::initialize(const NativeWindow *native) +{ + mNative = native; + mDisplay->mFunctionsGL->genFramebuffers(1, &mGLFB); + return resize(native->width, native->height); +} + +bool DisplayOzone::Buffer::initialize(int width, int height) +{ + mDisplay->mFunctionsGL->genFramebuffers(1, &mGLFB); + return resize(width, height); +} + +void DisplayOzone::Buffer::bindTexImage() +{ + mDisplay->mFunctionsGL->eglImageTargetTexture2DOES(GL_TEXTURE_2D, mImage); +} + +GLuint DisplayOzone::Buffer::getTexture() +{ + // TODO(fjhenigman) Try not to create a new texture every time. That already works on Intel + // and should work on Mali with proper fences. + FunctionsGL *gl = mDisplay->mFunctionsGL; + StateManagerGL *sm = mDisplay->getRenderer()->getStateManager(); + + gl->genTextures(1, &mTexture); + sm->bindTexture(GL_TEXTURE_2D, mTexture); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + ASSERT(mImage != EGL_NO_IMAGE_KHR); + gl->eglImageTargetTexture2DOES(GL_TEXTURE_2D, mImage); + return mTexture; +} + +uint32_t DisplayOzone::Buffer::getDRMFB() +{ + if (!mHasDRMFB) + { + int fd = gbm_device_get_fd(mDisplay->mGBM); + uint32_t handles[4] = {gbm_bo_get_handle(mBO).u32}; + uint32_t pitches[4] = {gbm_bo_get_stride(mBO)}; + uint32_t offsets[4] = {0}; + if (drmModeAddFB2(fd, mWidth, mHeight, mDRMFormatFB, handles, pitches, offsets, &mDRMFB, 0)) + { + std::cerr << "drmModeAddFB2 failed" << std::endl; + } + else + { + mHasDRMFB = true; + } + } + + return mDRMFB; +} + +FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::FramebufferState &state) +{ + return new FramebufferGL( + mGLFB, state, mDisplay->mFunctionsGL, mDisplay->getRenderer()->getWorkarounds(), + mDisplay->getRenderer()->getBlitter(), mDisplay->getRenderer()->getStateManager()); +} + +void DisplayOzone::Buffer::present() +{ + if (mNative) + { + if (mNative->visible) + { + mDisplay->drawBuffer(this); + } + resize(mNative->width, mNative->height); + } +} + +DisplayOzone::DisplayOzone() + : DisplayEGL(), + mSwapControl(SwapControl::ABSENT), + mMinSwapInterval(0), + mMaxSwapInterval(0), + mCurrentSwapInterval(-1), + mGBM(nullptr), + mConnector(nullptr), + mMode(nullptr), + mCRTC(nullptr), + mSetCRTC(true), + mWidth(0), + mHeight(0), + mScanning(nullptr), + mPending(nullptr), + mDrawing(nullptr), + mUnused(nullptr), + mProgram(0), + mVertexShader(0), + mFragmentShader(0), + mVertexBuffer(0), + mIndexBuffer(0), + mCenterUniform(0), + mWindowSizeUniform(0), + mBorderSizeUniform(0), + mDepthUniform(0) +{ +} + +DisplayOzone::~DisplayOzone() +{ +} + +egl::Error DisplayOzone::initialize(egl::Display *display) +{ + int fd; + char deviceName[30]; + drmModeResPtr resources = nullptr; + + for (int i = 0; i < 9; ++i) + { + snprintf(deviceName, sizeof(deviceName), "/dev/dri/card%d", i); + fd = open(deviceName, O_RDWR | O_CLOEXEC); + if (fd >= 0) + { + resources = drmModeGetResources(fd); + if (resources) + { + if (resources->count_connectors > 0) + { + break; + } + drmModeFreeResources(resources); + resources = nullptr; + } + close(fd); + } + } + if (!resources) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not open drm device."); + } + + mGBM = gbm_create_device(fd); + if (!mGBM) + { + close(fd); + drmModeFreeResources(resources); + return egl::Error(EGL_NOT_INITIALIZED, "Could not create gbm device."); + } + + mConnector = nullptr; + bool monitorConnected = false; + for (int i = 0; !mCRTC && i < resources->count_connectors; ++i) + { + drmModeFreeConnector(mConnector); + mConnector = drmModeGetConnector(fd, resources->connectors[i]); + if (!mConnector || mConnector->connection != DRM_MODE_CONNECTED) + { + continue; + } + monitorConnected = true; + mMode = ChooseMode(mConnector); + if (!mMode) + { + continue; + } + int n = ChooseCRTC(fd, mConnector); + if (n < 0) + { + continue; + } + mCRTC = drmModeGetCrtc(fd, resources->crtcs[n]); + } + drmModeFreeResources(resources); + + if (mCRTC) + { + mWidth = mMode->hdisplay; + mHeight = mMode->vdisplay; + } + else if (!monitorConnected) + { + // Even though there is no monitor to show it, we still do + // everything the same as if there were one, so we need an + // arbitrary size for our buffers. + mWidth = 1280; + mHeight = 1024; + } + else + { + return egl::Error(EGL_NOT_INITIALIZED, "Failed to choose mode/crtc."); + } + + // ANGLE builds its executables with an RPATH so they pull in ANGLE's libGL and libEGL. + // Here we need to open the native libEGL. An absolute path would work, but then we + // couldn't use LD_LIBRARY_PATH which is often useful during development. Instead we take + // advantage of the fact that the system lib is available under multiple names (for example + // with a .1 suffix) while Angle only installs libEGL.so. + FunctionsEGLDL *egl = new FunctionsEGLDL(); + mEGL = egl; + ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), "libEGL.so.1")); + + const char *necessaryExtensions[] = { + "EGL_KHR_image_base", "EGL_EXT_image_dma_buf_import", "EGL_KHR_surfaceless_context", + }; + for (auto &ext : necessaryExtensions) + { + if (!mEGL->hasExtension(ext)) + { + return egl::Error(EGL_NOT_INITIALIZED, "need %s", ext); + } + } + + if (mEGL->hasExtension("EGL_MESA_configless_context")) + { + mConfig = EGL_NO_CONFIG_MESA; + } + else + { + // clang-format off + const EGLint attrib[] = + { + // We want RGBA8 and DEPTH24_STENCIL8 + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE, + }; + // clang-format on + EGLint numConfig; + EGLConfig config[1]; + if (!mEGL->chooseConfig(attrib, config, 1, &numConfig) || numConfig < 1) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not get EGL config."); + } + mConfig = config[0]; + } + + ANGLE_TRY(initializeContext(display->getAttributeMap())); + + if (!mEGL->makeCurrent(EGL_NO_SURFACE, mContext)) + { + return egl::Error(EGL_NOT_INITIALIZED, "Could not make context current."); + } + + mFunctionsGL = mEGL->makeFunctionsGL(); + mFunctionsGL->initialize(); + + return DisplayGL::initialize(display); +} + +void DisplayOzone::pageFlipHandler(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *data) +{ + DisplayOzone *display = reinterpret_cast<DisplayOzone *>(data); + uint64_t tv = tv_sec; + display->pageFlipHandler(sequence, tv * 1000000 + tv_usec); +} + +void DisplayOzone::pageFlipHandler(unsigned int sequence, uint64_t tv) +{ + ASSERT(mPending); + mUnused = mScanning; + mScanning = mPending; + mPending = nullptr; +} + +void DisplayOzone::presentScreen() +{ + if (!mCRTC) + { + // no monitor + return; + } + + // see if pending flip has finished, without blocking + int fd = gbm_device_get_fd(mGBM); + if (mPending) + { + pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + if (poll(&pfd, 1, 0) < 0) + { + std::cerr << "poll failed: " << errno << " " << strerror(errno) << std::endl; + } + if (pfd.revents & POLLIN) + { + drmEventContext event; + event.version = DRM_EVENT_CONTEXT_VERSION; + event.page_flip_handler = pageFlipHandler; + drmHandleEvent(fd, &event); + } + } + + // if pending flip has finished, schedule next one + if (!mPending && mDrawing) + { + flushGL(); + if (mSetCRTC) + { + if (drmModeSetCrtc(fd, mCRTC->crtc_id, mDrawing->getDRMFB(), 0, 0, + &mConnector->connector_id, 1, mMode)) + { + std::cerr << "set crtc failed: " << errno << " " << strerror(errno) << std::endl; + } + mSetCRTC = false; + } + if (drmModePageFlip(fd, mCRTC->crtc_id, mDrawing->getDRMFB(), DRM_MODE_PAGE_FLIP_EVENT, + this)) + { + std::cerr << "page flip failed: " << errno << " " << strerror(errno) << std::endl; + } + mPending = mDrawing; + mDrawing = nullptr; + } +} + +GLuint DisplayOzone::makeShader(GLuint type, const char *src) +{ + FunctionsGL *gl = mFunctionsGL; + GLuint shader = gl->createShader(type); + gl->shaderSource(shader, 1, &src, nullptr); + gl->compileShader(shader); + + GLchar buf[999]; + GLsizei len; + GLint compiled; + gl->getShaderInfoLog(shader, sizeof(buf), &len, buf); + gl->getShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (compiled != GL_TRUE) + { + ANGLEPlatformCurrent()->logError("DisplayOzone shader compilation error:"); + ANGLEPlatformCurrent()->logError(buf); + } + + return shader; +} + +void DisplayOzone::drawWithTexture(Buffer *buffer) +{ + FunctionsGL *gl = mFunctionsGL; + StateManagerGL *sm = getRenderer()->getStateManager(); + + if (!mProgram) + { + const GLchar *vertexSource = + "#version 100\n" + "attribute vec3 vertex;\n" + "uniform vec2 center;\n" + "uniform vec2 windowSize;\n" + "uniform vec2 borderSize;\n" + "uniform float depth;\n" + "varying vec3 texCoord;\n" + "void main()\n" + "{\n" + " vec2 pos = vertex.xy * (windowSize + borderSize * vertex.z);\n" + " gl_Position = vec4(center + pos, depth, 1);\n" + " texCoord = vec3(pos / windowSize * vec2(.5, -.5) + vec2(.5, .5), vertex.z);\n" + "}\n"; + + const GLchar *fragmentSource = + "#version 100\n" + "precision mediump float;\n" + "uniform sampler2D tex;\n" + "varying vec3 texCoord;\n" + "void main()\n" + "{\n" + " if (texCoord.z > 0.)\n" + " {\n" + " float c = abs((texCoord.z * 2.) - 1.);\n" + " gl_FragColor = vec4(c, c, c, 1);\n" + " }\n" + " else\n" + " {\n" + " gl_FragColor = texture2D(tex, texCoord.xy);\n" + " }\n" + "}\n"; + + mVertexShader = makeShader(GL_VERTEX_SHADER, vertexSource); + mFragmentShader = makeShader(GL_FRAGMENT_SHADER, fragmentSource); + mProgram = gl->createProgram(); + gl->attachShader(mProgram, mVertexShader); + gl->attachShader(mProgram, mFragmentShader); + gl->bindAttribLocation(mProgram, 0, "vertex"); + gl->linkProgram(mProgram); + GLint linked; + gl->getProgramiv(mProgram, GL_LINK_STATUS, &linked); + ASSERT(linked); + mCenterUniform = gl->getUniformLocation(mProgram, "center"); + mWindowSizeUniform = gl->getUniformLocation(mProgram, "windowSize"); + mBorderSizeUniform = gl->getUniformLocation(mProgram, "borderSize"); + mDepthUniform = gl->getUniformLocation(mProgram, "depth"); + GLint texUniform = gl->getUniformLocation(mProgram, "tex"); + sm->useProgram(mProgram); + gl->uniform1i(texUniform, 0); + + // clang-format off + const GLfloat vertices[] = + { + // window corners, and window border inside corners + 1, -1, 0, + -1, -1, 0, + 1, 1, 0, + -1, 1, 0, + // window border outside corners + 1, -1, 1, + -1, -1, 1, + 1, 1, 1, + -1, 1, 1, + }; + // clang-format on + gl->genBuffers(1, &mVertexBuffer); + sm->bindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); + gl->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // window border triangle strip + const GLuint borderStrip[] = {5, 0, 4, 2, 6, 3, 7, 1, 5, 0}; + + gl->genBuffers(1, &mIndexBuffer); + sm->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); + gl->bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(borderStrip), borderStrip, GL_STATIC_DRAW); + } + else + { + sm->useProgram(mProgram); + sm->bindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); + sm->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); + } + + // convert from pixels to "-1 to 1" space + const NativeWindow *n = buffer->getNative(); + double x = n->x * 2. / mWidth - 1; + double y = n->y * 2. / mHeight - 1; + double halfw = n->width * 1. / mWidth; + double halfh = n->height * 1. / mHeight; + double borderw = n->borderWidth * 2. / mWidth; + double borderh = n->borderHeight * 2. / mHeight; + + gl->uniform2f(mCenterUniform, x + halfw, y + halfh); + gl->uniform2f(mWindowSizeUniform, halfw, halfh); + gl->uniform2f(mBorderSizeUniform, borderw, borderh); + gl->uniform1f(mDepthUniform, n->depth / 1e6); + + sm->setBlendEnabled(false); + sm->setCullFaceEnabled(false); + sm->setStencilTestEnabled(false); + sm->setScissorTestEnabled(false); + sm->setDepthTestEnabled(true); + sm->setColorMask(true, true, true, true); + sm->setDepthMask(true); + sm->setDepthRange(0, 1); + sm->setDepthFunc(GL_LESS); + sm->setViewport(gl::Rectangle(0, 0, mWidth, mHeight)); + sm->activeTexture(0); + GLuint tex = buffer->getTexture(); + sm->bindTexture(GL_TEXTURE_2D, tex); + gl->vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + gl->enableVertexAttribArray(0); + sm->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawing->getGLFB()); + gl->drawArrays(GL_TRIANGLE_STRIP, 0, 4); + gl->drawElements(GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, 0); + sm->deleteTexture(tex); +} + +void DisplayOzone::drawBuffer(Buffer *buffer) +{ + if (!mDrawing) + { + // get buffer on which to draw window + if (mUnused) + { + mDrawing = mUnused; + mUnused = nullptr; + } + else + { + mDrawing = new Buffer(this, GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT, + GBM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, + true, true); // XXX shouldn't need stencil + if (!mDrawing || !mDrawing->initialize(mWidth, mHeight)) + { + return; + } + } + + StateManagerGL *sm = getRenderer()->getStateManager(); + sm->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawing->getGLFB()); + sm->setClearColor(gl::ColorF(0, 0, 0, 1)); + sm->setClearDepth(1); + sm->setScissorTestEnabled(false); + sm->setColorMask(true, true, true, true); + sm->setDepthMask(true); + mFunctionsGL->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + drawWithTexture(buffer); + presentScreen(); +} + +void DisplayOzone::flushGL() +{ + mFunctionsGL->flush(); + if (mEGL->hasExtension("EGL_KHR_fence_sync")) + { + const EGLint attrib[] = {EGL_SYNC_CONDITION_KHR, + EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, EGL_NONE}; + EGLSyncKHR fence = mEGL->createSyncKHR(EGL_SYNC_FENCE_KHR, attrib); + if (fence) + { + // TODO(fjhenigman) Figure out the right way to use fences on Mali GPU + // to maximize throughput and avoid hangs when a program is interrupted. + // This busy wait was an attempt to reduce hangs when interrupted by SIGINT, + // but we still get some. + for (;;) + { + EGLint r = mEGL->clientWaitSyncKHR(fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 0); + if (r != EGL_TIMEOUT_EXPIRED_KHR) + { + break; + } + usleep(99); + } + mEGL->destroySyncKHR(fence); + return; + } + } +} + +void DisplayOzone::terminate() +{ + SafeDelete(mScanning); + SafeDelete(mPending); + SafeDelete(mDrawing); + SafeDelete(mUnused); + + if (mProgram) + { + mFunctionsGL->deleteProgram(mProgram); + mFunctionsGL->deleteShader(mVertexShader); + mFunctionsGL->deleteShader(mFragmentShader); + mFunctionsGL->deleteBuffers(1, &mVertexBuffer); + mFunctionsGL->deleteBuffers(1, &mIndexBuffer); + mProgram = 0; + } + + DisplayGL::terminate(); + + if (mContext) + { + // Mesa might crash if you terminate EGL with a context current + // then re-initialize EGL, so make our context not current. + mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT); + mEGL->destroyContext(mContext); + mContext = nullptr; + } + + SafeDelete(mFunctionsGL); + + if (mEGL) + { + mEGL->terminate(); + SafeDelete(mEGL); + } + + drmModeFreeCrtc(mCRTC); + + if (mGBM) + { + int fd = gbm_device_get_fd(mGBM); + gbm_device_destroy(mGBM); + mGBM = nullptr; + close(fd); + } +} + +SurfaceImpl *DisplayOzone::createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) +{ + Buffer *buffer = new Buffer(this, GBM_BO_USE_RENDERING, GBM_FORMAT_ARGB8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, true, true); + if (!buffer || !buffer->initialize(reinterpret_cast<const NativeWindow *>(window))) + { + return nullptr; + } + return new SurfaceOzone(state, getRenderer(), buffer); +} + +SurfaceImpl *DisplayOzone::createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) +{ + EGLAttrib width = attribs.get(EGL_WIDTH, 0); + EGLAttrib height = attribs.get(EGL_HEIGHT, 0); + Buffer *buffer = new Buffer(this, GBM_BO_USE_RENDERING, GBM_FORMAT_ARGB8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, true, true); + if (!buffer || !buffer->initialize(width, height)) + { + return nullptr; + } + return new SurfaceOzone(state, getRenderer(), buffer); +} + +SurfaceImpl *DisplayOzone::createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +SurfaceImpl *DisplayOzone::createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) +{ + UNIMPLEMENTED(); + return nullptr; +} + +egl::Error DisplayOzone::getDevice(DeviceImpl **device) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_BAD_DISPLAY); +} + +egl::ConfigSet DisplayOzone::generateConfigs() +{ + egl::ConfigSet configs; + + egl::Config config; + config.redSize = 8; + config.greenSize = 8; + config.blueSize = 8; + config.alphaSize = 8; + config.depthSize = 24; + config.stencilSize = 8; + config.bindToTextureRGBA = EGL_TRUE; + config.renderableType = EGL_OPENGL_ES2_BIT; + config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; + + configs.add(config); + return configs; +} + +bool DisplayOzone::testDeviceLost() +{ + return false; +} + +egl::Error DisplayOzone::restoreLostDevice() +{ + UNIMPLEMENTED(); + return egl::Error(EGL_BAD_DISPLAY); +} + +bool DisplayOzone::isValidNativeWindow(EGLNativeWindowType window) const +{ + return true; +} + +egl::Error DisplayOzone::getDriverVersion(std::string *version) const +{ + *version = ""; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayOzone::waitClient() const +{ + // TODO(fjhenigman) Implement this. + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayOzone::waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const +{ + // TODO(fjhenigman) Implement this. + return egl::Error(EGL_SUCCESS); +} + +void DisplayOzone::setSwapInterval(EGLSurface drawable, SwapControlData *data) +{ + ASSERT(data != nullptr); +} + +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h new file mode 100755 index 000000000..77c669314 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h @@ -0,0 +1,211 @@ +// +// Copyright (c) 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. +// + +// DisplayOzone.h: Ozone implementation of egl::Display + +#ifndef LIBANGLE_RENDERER_GL_EGL_OZONE_DISPLAYOZONE_H_ +#define LIBANGLE_RENDERER_GL_EGL_OZONE_DISPLAYOZONE_H_ + +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include <string> + +#include "libANGLE/renderer/gl/egl/DisplayEGL.h" + +struct gbm_device; +struct gbm_bo; + +namespace gl +{ +class FramebufferState; +} + +namespace rx +{ + +class FramebufferGL; + +// TODO(fjhenigman) Implement swap control. The following struct will be used for that. +// State-tracking data for the swap control to allow DisplayOzone to remember per +// drawable information for swap control. +struct SwapControlData final +{ + SwapControlData(); + + // Set by the drawable + int targetSwapInterval; + + // DisplayOzone-side state-tracking + int maxSwapInterval; + int currentSwapInterval; +}; + +class DisplayOzone final : public DisplayEGL +{ + public: + struct NativeWindow + { + int32_t x; + int32_t y; + int32_t width; + int32_t height; + int32_t borderWidth; + int32_t borderHeight; + int32_t visible; + int32_t depth; + }; + + class Buffer final : angle::NonCopyable + { + public: + Buffer(DisplayOzone *display, + uint32_t useFlags, + uint32_t gbmFormat, + uint32_t drmFormat, + uint32_t drmFormatFB, + int depthBits, + int stencilBits); + + ~Buffer(); + bool initialize(const NativeWindow *window); + bool initialize(int32_t width, int32_t height); + void reset(); + bool resize(int32_t width, int32_t height); + FramebufferGL *framebufferGL(const gl::FramebufferState &state); + void present(); + uint32_t getDRMFB(); + void bindTexImage(); + GLuint getTexture(); + int32_t getWidth() const { return mWidth; } + int32_t getHeight() const { return mHeight; } + GLuint getGLFB() const { return mGLFB; } + const NativeWindow *getNative() const { return mNative; } + + private: + DisplayOzone *mDisplay; + const NativeWindow *mNative; + int mWidth; + int mHeight; + const int mDepthBits; + const int mStencilBits; + const uint32_t mUseFlags; + const uint32_t mGBMFormat; + const uint32_t mDRMFormat; + const uint32_t mDRMFormatFB; + gbm_bo *mBO; + int mDMABuf; + bool mHasDRMFB; + uint32_t mDRMFB; + EGLImageKHR mImage; + GLuint mColorBuffer; + GLuint mDSBuffer; + GLuint mGLFB; + GLuint mTexture; + }; + + DisplayOzone(); + ~DisplayOzone() override; + + egl::Error initialize(egl::Display *display) override; + void terminate() override; + + SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) override; + SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, + const egl::Config *configuration, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) override; + + egl::ConfigSet generateConfigs() override; + + bool testDeviceLost() override; + egl::Error restoreLostDevice() override; + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + + egl::Error getDevice(DeviceImpl **device) override; + + egl::Error waitClient() const override; + egl::Error waitNative(EGLint engine, + egl::Surface *drawSurface, + egl::Surface *readSurface) const override; + + // TODO(fjhenigman) Implement this. + // Swap interval can be set globally or per drawable. + // This function will make sure the drawable's swap interval is the + // one required so that the subsequent swapBuffers acts as expected. + void setSwapInterval(EGLSurface drawable, SwapControlData *data); + + egl::Error getDriverVersion(std::string *version) const override; + + private: + GLuint makeShader(GLuint type, const char *src); + void drawBuffer(Buffer *buffer); + void drawWithBlit(Buffer *buffer); + void drawWithTexture(Buffer *buffer); + void flushGL(); + void presentScreen(); + static void pageFlipHandler(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *data); + void pageFlipHandler(unsigned int sequence, uint64_t tv); + + // TODO(fjhenigman) Implement swap control. The following stuff will be used for that. + enum class SwapControl + { + ABSENT, + EXT, + MESA, + SGI, + }; + SwapControl mSwapControl; + int mMinSwapInterval; + int mMaxSwapInterval; + int mCurrentSwapInterval; + + gbm_device *mGBM; + drmModeConnectorPtr mConnector; + drmModeModeInfoPtr mMode; + drmModeCrtcPtr mCRTC; + bool mSetCRTC; + + int32_t mWidth; + int32_t mHeight; + + // Three scanout buffers cycle through four states. The state of a buffer + // is indicated by which of these pointers points to it. + // TODO(fjhenigman) It might be simpler/clearer to use a ring buffer. + Buffer *mScanning; + Buffer *mPending; + Buffer *mDrawing; + Buffer *mUnused; + + GLuint mProgram; + GLuint mVertexShader; + GLuint mFragmentShader; + GLuint mVertexBuffer; + GLuint mIndexBuffer; + GLint mCenterUniform; + GLint mWindowSizeUniform; + GLint mBorderSizeUniform; + GLint mDepthUniform; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_OZONE_DISPLAYOZONE_H_ diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.cpp b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.cpp new file mode 100755 index 000000000..614fed0fd --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.cpp @@ -0,0 +1,98 @@ +// +// Copyright (c) 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. +// + +// SurfaceOzone.cpp: Ozone implementation of egl::SurfaceGL + +#include "libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h" + +#include "libANGLE/renderer/gl/FramebufferGL.h" +#include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h" + +namespace rx +{ + +SurfaceOzone::SurfaceOzone(const egl::SurfaceState &state, + RendererGL *renderer, + DisplayOzone::Buffer *buffer) + : SurfaceGL(state, renderer), mBuffer(buffer) +{ +} + +SurfaceOzone::~SurfaceOzone() +{ + delete mBuffer; +} + +egl::Error SurfaceOzone::initialize() +{ + return egl::Error(EGL_SUCCESS); +} + +FramebufferImpl *SurfaceOzone::createDefaultFramebuffer(const gl::FramebufferState &state) +{ + return mBuffer->framebufferGL(state); +} + +egl::Error SurfaceOzone::makeCurrent() +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceOzone::swap() +{ + mBuffer->present(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceOzone::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceOzone::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + UNIMPLEMENTED(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceOzone::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + mBuffer->bindTexImage(); + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceOzone::releaseTexImage(EGLint buffer) +{ + return egl::Error(EGL_SUCCESS); +} + +void SurfaceOzone::setSwapInterval(EGLint interval) +{ + mSwapControl.targetSwapInterval = interval; +} + +EGLint SurfaceOzone::getWidth() const +{ + return mBuffer->getWidth(); +} + +EGLint SurfaceOzone::getHeight() const +{ + return mBuffer->getHeight(); +} + +EGLint SurfaceOzone::isPostSubBufferSupported() const +{ + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLint SurfaceOzone::getSwapBehavior() const +{ + return EGL_BUFFER_PRESERVED; +} +} // namespace rx diff --git a/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h new file mode 100755 index 000000000..24b8ec8c9 --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 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. +// + +// SurfaceOzone.h: Ozone implementation of egl::SurfaceGL + +#ifndef LIBANGLE_RENDERER_GL_EGL_OZONE_SURFACEOZONE_H_ +#define LIBANGLE_RENDERER_GL_EGL_OZONE_SURFACEOZONE_H_ + +#include "libANGLE/renderer/gl/SurfaceGL.h" +#include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h" + +namespace rx +{ + +class SurfaceOzone : public SurfaceGL +{ + public: + SurfaceOzone(const egl::SurfaceState &state, + RendererGL *renderer, + DisplayOzone::Buffer *buffer); + ~SurfaceOzone() override; + + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; + + egl::Error initialize() override; + egl::Error makeCurrent() override; + + egl::Error swap() override; + egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; + egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override; + egl::Error releaseTexImage(EGLint buffer) override; + void setSwapInterval(EGLint interval) override; + + EGLint getWidth() const override; + EGLint getHeight() const override; + + EGLint isPostSubBufferSupported() const override; + EGLint getSwapBehavior() const override; + + private: + DisplayOzone::Buffer *mBuffer; + + // TODO(fjhenigman) Implement swap control. This will be used for that. + SwapControlData mSwapControl; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_GL_EGL_OZONE_SURFACEOZONE_H_ |