| /*------------------------------------------------------------------------- | |
| * drawElements Quality Program Tester Core | |
| * ---------------------------------------- | |
| * | |
| * Copyright 2014 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| * | |
| */ | |
| #include "egluNativeDisplay.hpp" | |
| #include "tcuANGLENativeDisplayFactory.h" | |
| #include <EGL/egl.h> | |
| #include <EGL/eglext.h> | |
| #include "deClock.h" | |
| #include "deMemory.h" | |
| #include "egluDefs.hpp" | |
| #include "eglwLibrary.hpp" | |
| #include "tcuTexture.hpp" | |
| #include "util/OSPixmap.h" | |
| #include "util/OSWindow.h" | |
| // clang-format off | |
| #if (DE_OS == DE_OS_WIN32) | |
| #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".dll" | |
| #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID) | |
| #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".so" | |
| #elif (DE_OS == DE_OS_OSX) | |
| #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".dylib" | |
| #else | |
| #error "Unsupported platform" | |
| #endif | |
| // clang-format on | |
| namespace tcu | |
| { | |
| namespace | |
| { | |
| enum | |
| { | |
| DEFAULT_SURFACE_WIDTH = 400, | |
| DEFAULT_SURFACE_HEIGHT = 300, | |
| }; | |
| constexpr eglu::NativeDisplay::Capability kDisplayCapabilities = | |
| static_cast<eglu::NativeDisplay::Capability>( | |
| eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM | | |
| eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM_EXT); | |
| constexpr eglu::NativePixmap::Capability kBitmapCapabilities = | |
| eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY; | |
| constexpr eglu::NativeWindow::Capability kWindowCapabilities = | |
| static_cast<eglu::NativeWindow::Capability>( | |
| eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY | | |
| eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE | | |
| eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE | | |
| eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS | | |
| eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE | | |
| eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY); | |
| class ANGLENativeDisplay : public eglu::NativeDisplay | |
| { | |
| public: | |
| explicit ANGLENativeDisplay(std::vector<eglw::EGLAttrib> attribs); | |
| ~ANGLENativeDisplay() override = default; | |
| void *getPlatformNative() override | |
| { | |
| // On OSX 64bits mDeviceContext is a 32 bit integer, so we can't simply | |
| // use reinterpret_cast<void*>. | |
| void *result = nullptr; | |
| memcpy(&result, &mDeviceContext, sizeof(mDeviceContext)); | |
| return result; | |
| } | |
| const eglw::EGLAttrib *getPlatformAttributes() const override | |
| { | |
| return &mPlatformAttributes[0]; | |
| } | |
| const eglw::Library &getLibrary() const override { return mLibrary; } | |
| EGLNativeDisplayType getDeviceContext() const { return mDeviceContext; } | |
| private: | |
| EGLNativeDisplayType mDeviceContext; | |
| eglw::DefaultLibrary mLibrary; | |
| std::vector<eglw::EGLAttrib> mPlatformAttributes; | |
| }; | |
| class NativePixmapFactory : public eglu::NativePixmapFactory | |
| { | |
| public: | |
| NativePixmapFactory(); | |
| ~NativePixmapFactory() override = default; | |
| eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay, | |
| int width, | |
| int height) const override; | |
| eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay, | |
| eglw::EGLDisplay display, | |
| eglw::EGLConfig config, | |
| const eglw::EGLAttrib *attribList, | |
| int width, | |
| int height) const override; | |
| }; | |
| class NativePixmap : public eglu::NativePixmap | |
| { | |
| public: | |
| NativePixmap(EGLNativeDisplayType display, int width, int height, int bitDepth); | |
| virtual ~NativePixmap(); | |
| eglw::EGLNativePixmapType getLegacyNative() override; | |
| private: | |
| OSPixmap *mPixmap; | |
| }; | |
| class NativeWindowFactory : public eglu::NativeWindowFactory | |
| { | |
| public: | |
| explicit NativeWindowFactory(EventState *eventState); | |
| ~NativeWindowFactory() override = default; | |
| eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay, | |
| const eglu::WindowParams ¶ms) const override; | |
| eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay, | |
| eglw::EGLDisplay display, | |
| eglw::EGLConfig config, | |
| const eglw::EGLAttrib *attribList, | |
| const eglu::WindowParams ¶ms) const override; | |
| private: | |
| EventState *mEvents; | |
| }; | |
| class NativeWindow : public eglu::NativeWindow | |
| { | |
| public: | |
| NativeWindow(ANGLENativeDisplay *nativeDisplay, | |
| const eglu::WindowParams ¶ms, | |
| EventState *eventState); | |
| ~NativeWindow() override; | |
| eglw::EGLNativeWindowType getLegacyNative() override; | |
| IVec2 getSurfaceSize() const override; | |
| IVec2 getScreenSize() const override { return getSurfaceSize(); } | |
| void processEvents() override; | |
| void setSurfaceSize(IVec2 size) override; | |
| void setVisibility(eglu::WindowParams::Visibility visibility) override; | |
| void readScreenPixels(tcu::TextureLevel *dst) const override; | |
| private: | |
| OSWindow *mWindow; | |
| EventState *mEvents; | |
| }; | |
| // ANGLE NativeDisplay | |
| ANGLENativeDisplay::ANGLENativeDisplay(std::vector<EGLAttrib> attribs) | |
| : eglu::NativeDisplay(kDisplayCapabilities, EGL_PLATFORM_ANGLE_ANGLE, "EGL_EXT_platform_base"), | |
| mDeviceContext(EGL_DEFAULT_DISPLAY), | |
| mLibrary(ANGLE_EGL_LIBRARY_FULL_NAME), | |
| mPlatformAttributes(std::move(attribs)) | |
| {} | |
| // NativePixmap | |
| NativePixmap::NativePixmap(EGLNativeDisplayType display, int width, int height, int bitDepth) | |
| : eglu::NativePixmap(kBitmapCapabilities), mPixmap(CreateOSPixmap()) | |
| { | |
| #if (DE_OS != DE_OS_UNIX) | |
| throw tcu::NotSupportedError("Pixmap not supported"); | |
| #else | |
| if (!mPixmap) | |
| { | |
| throw ResourceError("Failed to create pixmap", DE_NULL, __FILE__, __LINE__); | |
| } | |
| if (!mPixmap->initialize(display, width, height, bitDepth)) | |
| { | |
| throw ResourceError("Failed to initialize pixmap", DE_NULL, __FILE__, __LINE__); | |
| } | |
| #endif | |
| } | |
| NativePixmap::~NativePixmap() | |
| { | |
| delete mPixmap; | |
| } | |
| eglw::EGLNativePixmapType NativePixmap::getLegacyNative() | |
| { | |
| return reinterpret_cast<eglw::EGLNativePixmapType>(mPixmap->getNativePixmap()); | |
| } | |
| // NativePixmapFactory | |
| NativePixmapFactory::NativePixmapFactory() | |
| : eglu::NativePixmapFactory("bitmap", "ANGLE Bitmap", kBitmapCapabilities) | |
| {} | |
| eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay, | |
| eglw::EGLDisplay display, | |
| eglw::EGLConfig config, | |
| const eglw::EGLAttrib *attribList, | |
| int width, | |
| int height) const | |
| { | |
| const eglw::Library &egl = nativeDisplay->getLibrary(); | |
| int redBits = 0; | |
| int greenBits = 0; | |
| int blueBits = 0; | |
| int alphaBits = 0; | |
| int bitSum = 0; | |
| DE_ASSERT(display != EGL_NO_DISPLAY); | |
| egl.getConfigAttrib(display, config, EGL_RED_SIZE, &redBits); | |
| egl.getConfigAttrib(display, config, EGL_GREEN_SIZE, &greenBits); | |
| egl.getConfigAttrib(display, config, EGL_BLUE_SIZE, &blueBits); | |
| egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaBits); | |
| EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()"); | |
| bitSum = redBits + greenBits + blueBits + alphaBits; | |
| return new NativePixmap(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay)->getDeviceContext(), | |
| width, height, bitSum); | |
| } | |
| eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay, | |
| int width, | |
| int height) const | |
| { | |
| const int defaultDepth = 32; | |
| return new NativePixmap(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay)->getDeviceContext(), | |
| width, height, defaultDepth); | |
| } | |
| // NativeWindowFactory | |
| NativeWindowFactory::NativeWindowFactory(EventState *eventState) | |
| : eglu::NativeWindowFactory("window", "ANGLE Window", kWindowCapabilities), mEvents(eventState) | |
| {} | |
| eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay, | |
| const eglu::WindowParams ¶ms) const | |
| { | |
| DE_ASSERT(DE_FALSE); | |
| return nullptr; | |
| } | |
| eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay, | |
| eglw::EGLDisplay display, | |
| eglw::EGLConfig config, | |
| const eglw::EGLAttrib *attribList, | |
| const eglu::WindowParams ¶ms) const | |
| { | |
| return new NativeWindow(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay), params, mEvents); | |
| } | |
| // NativeWindow | |
| NativeWindow::NativeWindow(ANGLENativeDisplay *nativeDisplay, | |
| const eglu::WindowParams ¶ms, | |
| EventState *eventState) | |
| : eglu::NativeWindow(kWindowCapabilities), mWindow(OSWindow::New()), mEvents(eventState) | |
| { | |
| bool initialized = mWindow->initialize( | |
| "dEQP ANGLE Tests", | |
| params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width, | |
| params.height == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT | |
| : params.height); | |
| TCU_CHECK(initialized); | |
| if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE) | |
| NativeWindow::setVisibility(params.visibility); | |
| } | |
| void NativeWindow::setVisibility(eglu::WindowParams::Visibility visibility) | |
| { | |
| switch (visibility) | |
| { | |
| case eglu::WindowParams::VISIBILITY_HIDDEN: | |
| mWindow->setVisible(false); | |
| break; | |
| case eglu::WindowParams::VISIBILITY_VISIBLE: | |
| case eglu::WindowParams::VISIBILITY_FULLSCREEN: | |
| mWindow->setVisible(true); | |
| break; | |
| default: | |
| DE_ASSERT(DE_FALSE); | |
| } | |
| } | |
| NativeWindow::~NativeWindow() | |
| { | |
| OSWindow::Delete(&mWindow); | |
| } | |
| eglw::EGLNativeWindowType NativeWindow::getLegacyNative() | |
| { | |
| return reinterpret_cast<eglw::EGLNativeWindowType>(mWindow->getNativeWindow()); | |
| } | |
| IVec2 NativeWindow::getSurfaceSize() const | |
| { | |
| return IVec2(mWindow->getWidth(), mWindow->getHeight()); | |
| } | |
| void NativeWindow::processEvents() | |
| { | |
| mWindow->messageLoop(); | |
| // Look for a quit event to forward to the EventState | |
| Event event = {}; | |
| while (mWindow->popEvent(&event)) | |
| { | |
| if (event.Type == Event::EVENT_CLOSED) | |
| { | |
| mEvents->signalQuitEvent(); | |
| } | |
| } | |
| } | |
| void NativeWindow::setSurfaceSize(IVec2 size) | |
| { | |
| mWindow->resize(size.x(), size.y()); | |
| } | |
| void NativeWindow::readScreenPixels(tcu::TextureLevel *dst) const | |
| { | |
| dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), | |
| mWindow->getWidth(), mWindow->getHeight()); | |
| if (!mWindow->takeScreenshot(reinterpret_cast<uint8_t *>(dst->getAccess().getDataPtr()))) | |
| { | |
| throw InternalError("Failed to read screen pixels", DE_NULL, __FILE__, __LINE__); | |
| } | |
| } | |
| } // namespace | |
| ANGLENativeDisplayFactory::ANGLENativeDisplayFactory( | |
| const std::string &name, | |
| const std::string &description, | |
| std::vector<eglw::EGLAttrib> platformAttributes, | |
| EventState *eventState) | |
| : eglu::NativeDisplayFactory(name, | |
| description, | |
| kDisplayCapabilities, | |
| EGL_PLATFORM_ANGLE_ANGLE, | |
| "EGL_EXT_platform_base"), | |
| mPlatformAttributes(std::move(platformAttributes)) | |
| { | |
| m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(eventState)); | |
| m_nativePixmapRegistry.registerFactory(new NativePixmapFactory()); | |
| } | |
| ANGLENativeDisplayFactory::~ANGLENativeDisplayFactory() = default; | |
| eglu::NativeDisplay *ANGLENativeDisplayFactory::createDisplay( | |
| const eglw::EGLAttrib *attribList) const | |
| { | |
| DE_UNREF(attribList); | |
| return new ANGLENativeDisplay(mPlatformAttributes); | |
| } | |
| } // namespace tcu |