| /*------------------------------------------------------------------------- |
| * 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 |