diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/tests/egl_tests | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/tests/egl_tests')
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLContextCompatibilityTest.cpp | 287 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLContextSharingTest.cpp | 87 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLDeviceTest.cpp | 587 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp | 378 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLQueryContextTest.cpp | 153 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLRobustnessTest.cpp | 234 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLSanityCheckTest.cpp | 30 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp | 547 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLSurfaceTest.cpp | 517 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLThreadTest.cpp | 83 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLX11VisualTest.cpp | 216 | ||||
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/media/yuvtest.inl | 1548 |
12 files changed, 4667 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/egl_tests/EGLContextCompatibilityTest.cpp b/gfx/angle/src/tests/egl_tests/EGLContextCompatibilityTest.cpp new file mode 100755 index 000000000..63c58afba --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLContextCompatibilityTest.cpp @@ -0,0 +1,287 @@ +// +// Copyright (c) 2015 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. +// + +// EGLContextCompatibilityTest.cpp: +// This test will try to use all combinations of context configs and +// surface configs. If the configs are compatible, it checks that simple +// rendering works, otherwise it checks an error is generated one MakeCurrent. +#include <gtest/gtest.h> + +#include <vector> +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "OSWindow.h" +#include "test_utils/ANGLETest.h" +#include "test_utils/angle_test_configs.h" + +using namespace angle; + +namespace +{ + +const EGLint contextAttribs[] = +{ + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE +}; + +} + +class EGLContextCompatibilityTest : public ANGLETest +{ + public: + EGLContextCompatibilityTest() + : mDisplay(0) + { + } + + void SetUp() override + { + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT")); + ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr); + + EGLint dispattrs[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), + EGL_NONE + }; + mDisplay = eglGetPlatformDisplayEXT( + EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs); + ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); + + ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE); + + int nConfigs = 0; + ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE); + ASSERT_TRUE(nConfigs != 0); + + int nReturnedConfigs = 0; + mConfigs.resize(nConfigs); + ASSERT_TRUE(eglGetConfigs(mDisplay, mConfigs.data(), nConfigs, &nReturnedConfigs) == EGL_TRUE); + ASSERT_TRUE(nConfigs == nReturnedConfigs); + } + + void TearDown() override + { + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(mDisplay); + }; + + protected: + bool areConfigsCompatible(EGLConfig c1, EGLConfig c2, EGLint surfaceBit) + { + EGLint colorBufferType1, colorBufferType2; + EGLint red1, red2, green1, green2, blue1, blue2, alpha1, alpha2; + EGLint depth1, depth2, stencil1, stencil2; + EGLint surfaceType1, surfaceType2; + + eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_BUFFER_TYPE, &colorBufferType1); + eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_BUFFER_TYPE, &colorBufferType2); + + eglGetConfigAttrib(mDisplay, c1, EGL_RED_SIZE, &red1); + eglGetConfigAttrib(mDisplay, c2, EGL_RED_SIZE, &red2); + eglGetConfigAttrib(mDisplay, c1, EGL_GREEN_SIZE, &green1); + eglGetConfigAttrib(mDisplay, c2, EGL_GREEN_SIZE, &green2); + eglGetConfigAttrib(mDisplay, c1, EGL_BLUE_SIZE, &blue1); + eglGetConfigAttrib(mDisplay, c2, EGL_BLUE_SIZE, &blue2); + eglGetConfigAttrib(mDisplay, c1, EGL_ALPHA_SIZE, &alpha1); + eglGetConfigAttrib(mDisplay, c2, EGL_ALPHA_SIZE, &alpha2); + + eglGetConfigAttrib(mDisplay, c1, EGL_DEPTH_SIZE, &depth1); + eglGetConfigAttrib(mDisplay, c2, EGL_DEPTH_SIZE, &depth2); + eglGetConfigAttrib(mDisplay, c1, EGL_STENCIL_SIZE, &stencil1); + eglGetConfigAttrib(mDisplay, c2, EGL_STENCIL_SIZE, &stencil2); + + eglGetConfigAttrib(mDisplay, c1, EGL_SURFACE_TYPE, &surfaceType1); + eglGetConfigAttrib(mDisplay, c2, EGL_SURFACE_TYPE, &surfaceType2); + + return colorBufferType1 == colorBufferType2 && + red1 == red2 && green1 == green2 && blue1 == blue2 && alpha1 == alpha2 && + depth1 == depth2 && stencil1 == stencil2 && + (surfaceType1 & surfaceBit) != 0 && + (surfaceType2 & surfaceBit) != 0; + } + + void testWindowCompatibility(EGLConfig windowConfig, EGLConfig contextConfig, bool compatible) const + { + OSWindow *osWindow = CreateOSWindow(); + ASSERT_TRUE(osWindow != nullptr); + osWindow->initialize("EGLContextCompatibilityTest", 500, 500); + osWindow->setVisible(true); + + EGLContext context = eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, contextAttribs); + ASSERT_TRUE(context != EGL_NO_CONTEXT); + + EGLSurface window = eglCreateWindowSurface(mDisplay, windowConfig, osWindow->getNativeWindow(), nullptr); + ASSERT_EGL_SUCCESS(); + + if (compatible) + { + testClearSurface(window, context); + } + else + { + testMakeCurrentFails(window, context); + } + + eglDestroySurface(mDisplay, window); + ASSERT_EGL_SUCCESS(); + + eglDestroyContext(mDisplay, context); + ASSERT_EGL_SUCCESS(); + + SafeDelete(osWindow); + } + + void testPbufferCompatibility(EGLConfig pbufferConfig, EGLConfig contextConfig, bool compatible) const + { + EGLContext context = eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, contextAttribs); + ASSERT_TRUE(context != EGL_NO_CONTEXT); + + const EGLint pBufferAttribs[] = + { + EGL_WIDTH, 500, + EGL_HEIGHT, 500, + EGL_NONE, + }; + EGLSurface pbuffer = eglCreatePbufferSurface(mDisplay, pbufferConfig, pBufferAttribs); + ASSERT_TRUE(pbuffer != EGL_NO_SURFACE); + + if (compatible) + { + testClearSurface(pbuffer, context); + } + else + { + testMakeCurrentFails(pbuffer, context); + } + + eglDestroySurface(mDisplay, pbuffer); + ASSERT_EGL_SUCCESS(); + + eglDestroyContext(mDisplay, context); + ASSERT_EGL_SUCCESS(); + } + + std::vector<EGLConfig> mConfigs; + EGLDisplay mDisplay; + + private: + void testClearSurface(EGLSurface surface, EGLContext context) const + { + eglMakeCurrent(mDisplay, surface, surface, context); + ASSERT_EGL_SUCCESS(); + + glViewport(0, 0, 500, 500); + glClearColor(0.0f, 0.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + ASSERT_GL_NO_ERROR(); + EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255); + + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + ASSERT_EGL_SUCCESS(); + } + + void testMakeCurrentFails(EGLSurface surface, EGLContext context) const + { + eglMakeCurrent(mDisplay, surface, surface, context); + EXPECT_EGL_ERROR(EGL_BAD_MATCH); + } +}; + +// The test is split in several subtest so that simple cases +// are tested separately. Also each surface types are not tested +// together. + +// Basic test checking contexts and windows created with the +// same config can render. +TEST_P(EGLContextCompatibilityTest, WindowSameConfig) +{ + for (size_t i = 0; i < mConfigs.size(); i++) + { + EGLConfig config = mConfigs[i]; + + EGLint surfaceType; + eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType); + ASSERT_EGL_SUCCESS(); + + if ((surfaceType & EGL_WINDOW_BIT) != 0) + { + testWindowCompatibility(config, config, true); + } + } +} + +// Basic test checking contexts and pbuffers created with the +// same config can render. +TEST_P(EGLContextCompatibilityTest, PbufferSameConfig) +{ + for (size_t i = 0; i < mConfigs.size(); i++) + { + EGLConfig config = mConfigs[i]; + + EGLint surfaceType; + eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType); + ASSERT_EGL_SUCCESS(); + + if ((surfaceType & EGL_PBUFFER_BIT) != 0) + { + testPbufferCompatibility(config, config, true); + } + } +} + +// Check that a context rendering to a window with a different +// config works or errors according to the EGL compatibility rules +TEST_P(EGLContextCompatibilityTest, WindowDifferentConfig) +{ + for (size_t i = 0; i < mConfigs.size(); i++) + { + EGLConfig config1 = mConfigs[i]; + EGLint surfaceType; + eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType); + ASSERT_EGL_SUCCESS(); + + if ((surfaceType & EGL_WINDOW_BIT) == 0) + { + continue; + } + + for (size_t j = 0; j < mConfigs.size(); j++) + { + EGLConfig config2 = mConfigs[j]; + testWindowCompatibility(config1, config2, + areConfigsCompatible(config1, config2, EGL_WINDOW_BIT)); + } + } +} + +// Check that a context rendering to a pbuffer with a different +// config works or errors according to the EGL compatibility rules +TEST_P(EGLContextCompatibilityTest, PbufferDifferentConfig) +{ + for (size_t i = 0; i < mConfigs.size(); i++) + { + EGLConfig config1 = mConfigs[i]; + EGLint surfaceType; + eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType); + ASSERT_EGL_SUCCESS(); + + if ((surfaceType & EGL_PBUFFER_BIT) == 0) + { + continue; + } + + for (size_t j = 0; j < mConfigs.size(); j++) + { + EGLConfig config2 = mConfigs[j]; + testPbufferCompatibility(config1, config2, areConfigsCompatible(config1, config2, EGL_PBUFFER_BIT)); + } + } +} + +ANGLE_INSTANTIATE_TEST(EGLContextCompatibilityTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL()); diff --git a/gfx/angle/src/tests/egl_tests/EGLContextSharingTest.cpp b/gfx/angle/src/tests/egl_tests/EGLContextSharingTest.cpp new file mode 100755 index 000000000..fc66b7909 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLContextSharingTest.cpp @@ -0,0 +1,87 @@ +// +// 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. +// +// EGLContextSharingTest.cpp: +// Tests relating to shared Contexts. + +#include <gtest/gtest.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "test_utils/ANGLETest.h" +#include "test_utils/angle_test_configs.h" + +using namespace angle; + +namespace +{ + +EGLBoolean SafeDestroyContext(EGLDisplay display, EGLContext &context) +{ + EGLBoolean result = EGL_TRUE; + if (context != EGL_NO_CONTEXT) + { + result = eglDestroyContext(display, context); + context = EGL_NO_CONTEXT; + } + return result; +} + +class EGLContextSharingTest : public ANGLETest +{ + public: + EGLContextSharingTest() : mContexts{EGL_NO_CONTEXT, EGL_NO_CONTEXT}, mTexture(0) {} + + void TearDown() override + { + glDeleteTextures(1, &mTexture); + + EGLDisplay display = getEGLWindow()->getDisplay(); + + if (display != EGL_NO_DISPLAY) + { + for (auto &context : mContexts) + { + SafeDestroyContext(display, context); + } + } + + ANGLETest::TearDown(); + } + + EGLContext mContexts[2]; + GLuint mTexture; +}; + +// Tests that creating resources works after freeing the share context. +TEST_P(EGLContextSharingTest, BindTextureAfterShareContextFree) +{ + EGLDisplay display = getEGLWindow()->getDisplay(); + EGLConfig config = getEGLWindow()->getConfig(); + EGLSurface surface = getEGLWindow()->getSurface(); + + const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, + getEGLWindow()->getClientMajorVersion(), EGL_NONE}; + + mContexts[0] = eglCreateContext(display, config, nullptr, contextAttribs); + ASSERT_EGL_SUCCESS(); + ASSERT_TRUE(mContexts[0] != EGL_NO_CONTEXT); + mContexts[1] = eglCreateContext(display, config, mContexts[1], contextAttribs); + ASSERT_EGL_SUCCESS(); + ASSERT_TRUE(mContexts[1] != EGL_NO_CONTEXT); + + ASSERT_EGL_TRUE(SafeDestroyContext(display, mContexts[0])); + ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[1])); + ASSERT_EGL_SUCCESS(); + + glGenTextures(1, &mTexture); + glBindTexture(GL_TEXTURE_2D, mTexture); + ASSERT_GL_NO_ERROR(); +} + +} // anonymous namespace + +ANGLE_INSTANTIATE_TEST(EGLContextSharingTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL()); diff --git a/gfx/angle/src/tests/egl_tests/EGLDeviceTest.cpp b/gfx/angle/src/tests/egl_tests/EGLDeviceTest.cpp new file mode 100755 index 000000000..721754181 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLDeviceTest.cpp @@ -0,0 +1,587 @@ +// +// Copyright 2015 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. +// + +#ifndef ANGLE_ENABLE_D3D9 +#define ANGLE_ENABLE_D3D9 +#endif + +#ifndef ANGLE_ENABLE_D3D11 +#define ANGLE_ENABLE_D3D11 +#endif + +#include <d3d11.h> + +#include "com_utils.h" +#include "OSWindow.h" +#include "test_utils/ANGLETest.h" + +using namespace angle; + +class EGLDeviceCreationTest : public testing::Test +{ + protected: + EGLDeviceCreationTest() + : mD3D11Available(false), + mD3D11Module(nullptr), + mD3D11CreateDevice(nullptr), + mDevice(nullptr), + mDeviceContext(nullptr), + mDeviceCreationD3D11ExtAvailable(false), + mOSWindow(nullptr), + mDisplay(EGL_NO_DISPLAY), + mSurface(EGL_NO_SURFACE), + mContext(EGL_NO_CONTEXT), + mConfig(0) + { + } + + void SetUp() override + { + mD3D11Module = LoadLibrary(TEXT("d3d11.dll")); + if (mD3D11Module == nullptr) + { + std::cout << "Unable to LoadLibrary D3D11" << std::endl; + return; + } + + mD3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>( + GetProcAddress(mD3D11Module, "D3D11CreateDevice")); + if (mD3D11CreateDevice == nullptr) + { + std::cout << "Could not retrieve D3D11CreateDevice from d3d11.dll" << std::endl; + return; + } + + mD3D11Available = true; + + const char *extensionString = + static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); + if (strstr(extensionString, "EGL_ANGLE_device_creation")) + { + if (strstr(extensionString, "EGL_ANGLE_device_creation_d3d11")) + { + mDeviceCreationD3D11ExtAvailable = true; + } + } + } + + void TearDown() override + { + SafeRelease(mDevice); + SafeRelease(mDeviceContext); + + SafeDelete(mOSWindow); + + if (mSurface != EGL_NO_SURFACE) + { + eglDestroySurface(mDisplay, mSurface); + mSurface = EGL_NO_SURFACE; + } + + if (mContext != EGL_NO_CONTEXT) + { + eglDestroyContext(mDisplay, mContext); + mContext = EGL_NO_CONTEXT; + } + + if (mDisplay != EGL_NO_DISPLAY) + { + eglTerminate(mDisplay); + mDisplay = EGL_NO_DISPLAY; + } + } + + void CreateD3D11Device() + { + ASSERT_TRUE(mD3D11Available); + ASSERT_EQ(nullptr, mDevice); // The device shouldn't be created twice + + HRESULT hr = + mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, nullptr, 0, + D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, &mDeviceContext); + + ASSERT_TRUE(SUCCEEDED(hr)); + ASSERT_GE(mFeatureLevel, D3D_FEATURE_LEVEL_9_3); + } + + void CreateD3D11FL9_3Device() + { + ASSERT_TRUE(mD3D11Available); + ASSERT_EQ(nullptr, mDevice); + + D3D_FEATURE_LEVEL fl93 = D3D_FEATURE_LEVEL_9_3; + + HRESULT hr = + mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, &fl93, 1, D3D11_SDK_VERSION, + &mDevice, &mFeatureLevel, &mDeviceContext); + + ASSERT_TRUE(SUCCEEDED(hr)); + } + + void CreateWindowSurface() + { + EGLint majorVersion, minorVersion; + ASSERT_EGL_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion)); + + eglBindAPI(EGL_OPENGL_ES_API); + ASSERT_EGL_SUCCESS(); + + // Choose a config + const EGLint configAttributes[] = {EGL_NONE}; + EGLint configCount = 0; + ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount)); + + // Create an OS Window + mOSWindow = CreateOSWindow(); + mOSWindow->initialize("EGLSurfaceTest", 64, 64); + + // Create window surface + mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr); + ASSERT_EGL_SUCCESS(); + + // Create EGL context + EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes); + ASSERT_EGL_SUCCESS(); + + // Make the surface current + eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); + ASSERT_EGL_SUCCESS(); + } + + // This triggers a D3D device lost on current Windows systems + // This behavior could potentially change in the future + void trigger9_3DeviceLost() + { + ID3D11Buffer *gsBuffer = nullptr; + D3D11_BUFFER_DESC bufferDesc = {0}; + bufferDesc.ByteWidth = 64; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + HRESULT result = mDevice->CreateBuffer(&bufferDesc, nullptr, &gsBuffer); + ASSERT_TRUE(SUCCEEDED(result)); + + mDeviceContext->GSSetConstantBuffers(0, 1, &gsBuffer); + SafeRelease(gsBuffer); + gsBuffer = nullptr; + + result = mDevice->GetDeviceRemovedReason(); + ASSERT_TRUE(FAILED(result)); + } + + bool mD3D11Available; + HMODULE mD3D11Module; + PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice; + + ID3D11Device *mDevice; + ID3D11DeviceContext *mDeviceContext; + D3D_FEATURE_LEVEL mFeatureLevel; + + bool mDeviceCreationD3D11ExtAvailable; + + OSWindow *mOSWindow; + + EGLDisplay mDisplay; + EGLSurface mSurface; + EGLContext mContext; + EGLConfig mConfig; +}; + +// Test that creating a EGLDeviceEXT from D3D11 device works, and it can be queried to retrieve +// D3D11 device +TEST_F(EGLDeviceCreationTest, BasicD3D11Device) +{ + if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available) + { + std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl; + return; + } + + CreateD3D11Device(); + + EGLDeviceEXT eglDevice = + eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr); + ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice); + ASSERT_EGL_SUCCESS(); + + EGLAttrib deviceAttrib; + eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, &deviceAttrib); + ASSERT_EGL_SUCCESS(); + + ID3D11Device *queriedDevice = reinterpret_cast<ID3D11Device *>(deviceAttrib); + ASSERT_EQ(mFeatureLevel, queriedDevice->GetFeatureLevel()); + + eglReleaseDeviceANGLE(eglDevice); +} + +// Test that creating a EGLDeviceEXT from D3D11 device works, and it can be queried to retrieve +// D3D11 device +TEST_F(EGLDeviceCreationTest, BasicD3D11DeviceViaFuncPointer) +{ + if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available) + { + std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl; + return; + } + + CreateD3D11Device(); + + PFNEGLCREATEDEVICEANGLEPROC createDeviceANGLE = + (PFNEGLCREATEDEVICEANGLEPROC)eglGetProcAddress("eglCreateDeviceANGLE"); + PFNEGLRELEASEDEVICEANGLEPROC releaseDeviceANGLE = + (PFNEGLRELEASEDEVICEANGLEPROC)eglGetProcAddress("eglReleaseDeviceANGLE"); + + EGLDeviceEXT eglDevice = + createDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr); + ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice); + ASSERT_EGL_SUCCESS(); + + EGLAttrib deviceAttrib; + eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, &deviceAttrib); + ASSERT_EGL_SUCCESS(); + + ID3D11Device *queriedDevice = reinterpret_cast<ID3D11Device *>(deviceAttrib); + ASSERT_EQ(mFeatureLevel, queriedDevice->GetFeatureLevel()); + + releaseDeviceANGLE(eglDevice); +} + +// Test that creating a EGLDeviceEXT from D3D11 device works, and can be used for rendering +TEST_F(EGLDeviceCreationTest, RenderingUsingD3D11Device) +{ + if (!mD3D11Available) + { + std::cout << "D3D11 not available, skipping test" << std::endl; + return; + } + + CreateD3D11Device(); + + EGLDeviceEXT eglDevice = + eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr); + ASSERT_EGL_SUCCESS(); + + // Create an EGLDisplay using the EGLDevice + mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr); + ASSERT_NE(EGL_NO_DISPLAY, mDisplay); + + // Create a surface using the display + CreateWindowSurface(); + + // Perform some very basic rendering + glClearColor(1.0f, 0.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_PIXEL_EQ(32, 32, 255, 0, 255, 255); + + // Note that we must call TearDown() before we release the EGL device, since the display + // depends on the device + TearDown(); + + eglReleaseDeviceANGLE(eglDevice); +} + +// Test that ANGLE doesn't try to recreate a D3D11 device if the inputted one is lost +TEST_F(EGLDeviceCreationTest, D3D11DeviceRecovery) +{ + if (!mD3D11Available) + { + std::cout << "D3D11 not available, skipping test" << std::endl; + return; + } + + // Force Feature Level 9_3 so we can easily trigger a device lost later + CreateD3D11FL9_3Device(); + + EGLDeviceEXT eglDevice = + eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr); + ASSERT_EGL_SUCCESS(); + + // Create an EGLDisplay using the EGLDevice + mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr); + ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); + + // Create a surface using the display + CreateWindowSurface(); + + // Perform some very basic rendering + glClearColor(1.0f, 0.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_PIXEL_EQ(32, 32, 255, 0, 255, 255); + ASSERT_GL_NO_ERROR(); + + // ANGLE's SwapChain11::initPassThroughResources doesn't handle device lost before + // eglSwapBuffers, so we must call eglSwapBuffers before we lose the device. + ASSERT_EGL_TRUE(eglSwapBuffers(mDisplay, mSurface)); + + // Trigger a lost device + trigger9_3DeviceLost(); + + // Destroy the old EGL Window Surface + if (mSurface != EGL_NO_SURFACE) + { + eglDestroySurface(mDisplay, mSurface); + mSurface = EGL_NO_SURFACE; + } + + // Try to create a new window surface. In certain configurations this will recreate the D3D11 + // device. We want to test that it doesn't recreate the D3D11 device when EGLDeviceEXT is + // used. The window surface creation should fail if a new D3D11 device isn't created. + mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr); + ASSERT_EQ(EGL_NO_SURFACE, mSurface); + ASSERT_EGL_ERROR(EGL_BAD_ALLOC); + + // Get the D3D11 device out of the EGLDisplay again. It should be the same one as above. + EGLAttrib device = 0; + EGLAttrib newEglDevice = 0; + ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice)); + ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice), + EGL_D3D11_DEVICE_ANGLE, &device)); + ID3D11Device *newDevice = reinterpret_cast<ID3D11Device *>(device); + + ASSERT_EQ(reinterpret_cast<EGLDeviceEXT>(newEglDevice), eglDevice); + ASSERT_EQ(newDevice, mDevice); + + // Note that we must call TearDown() before we release the EGL device, since the display + // depends on the device + TearDown(); + + eglReleaseDeviceANGLE(eglDevice); +} + +// Test that calling eglGetPlatformDisplayEXT with the same device returns the same display +TEST_F(EGLDeviceCreationTest, getPlatformDisplayTwice) +{ + if (!mD3D11Available) + { + std::cout << "D3D11 not available, skipping test" << std::endl; + return; + } + + CreateD3D11Device(); + + EGLDeviceEXT eglDevice = + eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr); + ASSERT_EGL_SUCCESS(); + + // Create an EGLDisplay using the EGLDevice + EGLDisplay display1 = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr); + ASSERT_NE(EGL_NO_DISPLAY, display1); + + EGLDisplay display2 = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr); + ASSERT_NE(EGL_NO_DISPLAY, display2); + + ASSERT_EQ(display1, display2); + + eglTerminate(display1); + eglReleaseDeviceANGLE(eglDevice); +} + +// Test that creating a EGLDeviceEXT from an invalid D3D11 device fails +TEST_F(EGLDeviceCreationTest, InvalidD3D11Device) +{ + if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available) + { + std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl; + return; + } + + CreateD3D11Device(); + + // Use mDeviceContext instead of mDevice + EGLDeviceEXT eglDevice = eglCreateDeviceANGLE( + EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDeviceContext), nullptr); + EXPECT_EQ(EGL_NO_DEVICE_EXT, eglDevice); + EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE); +} + +// Test that EGLDeviceEXT holds a ref to the D3D11 device +TEST_F(EGLDeviceCreationTest, D3D11DeviceReferenceCounting) +{ + if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available) + { + std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl; + return; + } + + CreateD3D11Device(); + + EGLDeviceEXT eglDevice = + eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr); + ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice); + ASSERT_EGL_SUCCESS(); + + // Now release our D3D11 device/context + SafeRelease(mDevice); + SafeRelease(mDeviceContext); + + EGLAttrib deviceAttrib; + eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, &deviceAttrib); + ASSERT_EGL_SUCCESS(); + + ID3D11Device *queriedDevice = reinterpret_cast<ID3D11Device *>(deviceAttrib); + ASSERT_EQ(mFeatureLevel, queriedDevice->GetFeatureLevel()); + + eglReleaseDeviceANGLE(eglDevice); +} + +// Test that creating a EGLDeviceEXT from a D3D9 device fails +TEST_F(EGLDeviceCreationTest, AnyD3D9Device) +{ + if (!mDeviceCreationD3D11ExtAvailable) + { + std::cout << "EGLDevice creation not available, skipping test" << std::endl; + return; + } + + std::string fakeD3DDevice = "This is a string, not a D3D device"; + + EGLDeviceEXT eglDevice = eglCreateDeviceANGLE( + EGL_D3D9_DEVICE_ANGLE, reinterpret_cast<void *>(&fakeD3DDevice), nullptr); + EXPECT_EQ(EGL_NO_DEVICE_EXT, eglDevice); + EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE); +} + +class EGLDeviceQueryTest : public ANGLETest +{ + protected: + EGLDeviceQueryTest() + { + mQueryDisplayAttribEXT = nullptr; + mQueryDeviceAttribEXT = nullptr; + mQueryDeviceStringEXT = nullptr; + } + + void SetUp() override + { + ANGLETest::SetUp(); + + const char *extensionString = + static_cast<const char *>(eglQueryString(getEGLWindow()->getDisplay(), EGL_EXTENSIONS)); + if (strstr(extensionString, "EGL_EXT_device_query")) + { + mQueryDisplayAttribEXT = + (PFNEGLQUERYDISPLAYATTRIBEXTPROC)eglGetProcAddress("eglQueryDisplayAttribEXT"); + mQueryDeviceAttribEXT = + (PFNEGLQUERYDEVICEATTRIBEXTPROC)eglGetProcAddress("eglQueryDeviceAttribEXT"); + mQueryDeviceStringEXT = + (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT"); + } + + if (!mQueryDeviceStringEXT) + { + FAIL() << "ANGLE extension EGL_EXT_device_query export eglQueryDeviceStringEXT was not " + "found"; + } + + if (!mQueryDisplayAttribEXT) + { + FAIL() << "ANGLE extension EGL_EXT_device_query export eglQueryDisplayAttribEXT was " + "not found"; + } + + if (!mQueryDeviceAttribEXT) + { + FAIL() << "ANGLE extension EGL_EXT_device_query export eglQueryDeviceAttribEXT was not " + "found"; + } + + EGLAttrib angleDevice = 0; + EXPECT_EGL_TRUE( + mQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice)); + extensionString = static_cast<const char *>( + mQueryDeviceStringEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), EGL_EXTENSIONS)); + if (strstr(extensionString, "EGL_ANGLE_device_d3d") == NULL) + { + FAIL() << "ANGLE extension EGL_ANGLE_device_d3d was not found"; + } + } + + void TearDown() override { ANGLETest::TearDown(); } + + PFNEGLQUERYDISPLAYATTRIBEXTPROC mQueryDisplayAttribEXT; + PFNEGLQUERYDEVICEATTRIBEXTPROC mQueryDeviceAttribEXT; + PFNEGLQUERYDEVICESTRINGEXTPROC mQueryDeviceStringEXT; +}; + +// This test attempts to obtain a D3D11 device and a D3D9 device using the eglQueryDeviceAttribEXT +// function. +// If the test is configured to use D3D11 then it should succeed to obtain a D3D11 device. +// If the test is confitured to use D3D9, then it should succeed to obtain a D3D9 device. +TEST_P(EGLDeviceQueryTest, QueryDevice) +{ + EGLAttrib device = 0; + EGLAttrib angleDevice = 0; + if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + EXPECT_EGL_TRUE( + mQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice)); + EXPECT_EGL_TRUE(mQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), + EGL_D3D11_DEVICE_ANGLE, &device)); + ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device); + IDXGIDevice *dxgiDevice = DynamicCastComObject<IDXGIDevice>(d3d11Device); + EXPECT_TRUE(dxgiDevice != nullptr); + SafeRelease(dxgiDevice); + } + + if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) + { + EXPECT_EGL_TRUE( + mQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice)); + EXPECT_EGL_TRUE(mQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), + EGL_D3D9_DEVICE_ANGLE, &device)); + IDirect3DDevice9 *d3d9Device = reinterpret_cast<IDirect3DDevice9 *>(device); + IDirect3D9 *d3d9 = nullptr; + EXPECT_EQ(S_OK, d3d9Device->GetDirect3D(&d3d9)); + EXPECT_TRUE(d3d9 != nullptr); + SafeRelease(d3d9); + } +} + +// This test attempts to obtain a D3D11 device from a D3D9 configured system and a D3D9 device from +// a D3D11 configured system using the eglQueryDeviceAttribEXT function. +// If the test is configured to use D3D11 then it should fail to obtain a D3D11 device. +// If the test is confitured to use D3D9, then it should fail to obtain a D3D9 device. +TEST_P(EGLDeviceQueryTest, QueryDeviceBadAttribute) +{ + EGLAttrib device = 0; + EGLAttrib angleDevice = 0; + if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + EXPECT_EGL_TRUE( + mQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice)); + EXPECT_EGL_FALSE(mQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), + EGL_D3D9_DEVICE_ANGLE, &device)); + } + + if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) + { + EXPECT_EGL_TRUE( + mQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice)); + EXPECT_EGL_FALSE(mQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), + EGL_D3D11_DEVICE_ANGLE, &device)); + } +} + +// Ensure that: +// - calling getPlatformDisplayEXT using ANGLE_Platform with some parameters +// - extracting the EGLDeviceEXT from the EGLDisplay +// - calling getPlatformDisplayEXT with this EGLDeviceEXT +// results in the same EGLDisplay being returned from getPlatformDisplayEXT both times +TEST_P(EGLDeviceQueryTest, getPlatformDisplayDeviceReuse) +{ + EGLAttrib eglDevice = 0; + EXPECT_EGL_TRUE( + eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &eglDevice)); + + EGLDisplay display2 = eglGetPlatformDisplayEXT( + EGL_PLATFORM_DEVICE_EXT, reinterpret_cast<EGLDeviceEXT>(eglDevice), nullptr); + EXPECT_EQ(getEGLWindow()->getDisplay(), display2); +} + +// Use this to select which configurations (e.g. which renderer, which GLES major version) these +// tests should be run against. +ANGLE_INSTANTIATE_TEST(EGLDeviceQueryTest, ES2_D3D9(), ES2_D3D11()); diff --git a/gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp b/gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp new file mode 100755 index 000000000..c73c7c4ff --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp @@ -0,0 +1,378 @@ +// +// Copyright 2015 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. +// + +#include "test_utils/ANGLETest.h" + +#include <cstdint> +#include "com_utils.h" +#include "OSWindow.h" +#include <d3d11.h> + +using namespace angle; + +class EGLPresentPathD3D11 : public testing::TestWithParam<PlatformParameters> +{ + protected: + EGLPresentPathD3D11() + : mDisplay(EGL_NO_DISPLAY), + mContext(EGL_NO_CONTEXT), + mSurface(EGL_NO_SURFACE), + mOffscreenSurfaceD3D11Texture(nullptr), + mConfig(0), + mOSWindow(nullptr), + mWindowWidth(0) + { + } + + void SetUp() override + { + mOSWindow = CreateOSWindow(); + mWindowWidth = 64; + mOSWindow->initialize("EGLPresentPathD3D11", mWindowWidth, mWindowWidth); + } + + void initializeEGL(bool usePresentPathFast) + { + int clientVersion = GetParam().majorVersion; + + const char *extensionString = + static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); + ASSERT_NE(nullptr, strstr(extensionString, "EGL_ANGLE_experimental_present_path")); + + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + ASSERT_NE(nullptr, eglGetPlatformDisplayEXT); + + // Set up EGL Display + EGLint displayAttribs[] = { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, GetParam().eglParameters.majorVersion, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, GetParam().eglParameters.majorVersion, + EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, + usePresentPathFast ? EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE + : EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE, + EGL_NONE}; + mDisplay = + eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttribs); + ASSERT_TRUE(EGL_NO_DISPLAY != mDisplay); + ASSERT_EGL_TRUE(eglInitialize(mDisplay, NULL, NULL)); + + // Choose the EGL config + EGLint numConfigs; + EGLint configAttribs[] = {EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_RENDERABLE_TYPE, + clientVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_NONE}; + ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs)); + ASSERT_EQ(1, numConfigs); + + // Set up the EGL context + EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, clientVersion, EGL_NONE}; + mContext = eglCreateContext(mDisplay, mConfig, NULL, contextAttribs); + ASSERT_TRUE(EGL_NO_CONTEXT != mContext); + } + + void createWindowSurface() + { + mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr); + } + + void createPbufferFromClientBufferSurface() + { + EGLAttrib device = 0; + EGLAttrib angleDevice = 0; + + PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXT; + PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXT; + + const char *extensionString = + static_cast<const char *>(eglQueryString(mDisplay, EGL_EXTENSIONS)); + EXPECT_TRUE(strstr(extensionString, "EGL_EXT_device_query")); + + queryDisplayAttribEXT = + (PFNEGLQUERYDISPLAYATTRIBEXTPROC)eglGetProcAddress("eglQueryDisplayAttribEXT"); + queryDeviceAttribEXT = + (PFNEGLQUERYDEVICEATTRIBEXTPROC)eglGetProcAddress("eglQueryDeviceAttribEXT"); + ASSERT_NE(nullptr, queryDisplayAttribEXT); + ASSERT_NE(nullptr, queryDeviceAttribEXT); + + ASSERT_EGL_TRUE(queryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &angleDevice)); + ASSERT_EGL_TRUE(queryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), + EGL_D3D11_DEVICE_ANGLE, &device)); + ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device); + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + textureDesc.Width = mWindowWidth; + textureDesc.Height = mWindowWidth; + textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + + ASSERT_TRUE(SUCCEEDED( + d3d11Device->CreateTexture2D(&textureDesc, nullptr, &mOffscreenSurfaceD3D11Texture))); + + IDXGIResource *dxgiResource = + DynamicCastComObject<IDXGIResource>(mOffscreenSurfaceD3D11Texture); + ASSERT_NE(nullptr, dxgiResource); + + HANDLE sharedHandle = 0; + ASSERT_TRUE(SUCCEEDED(dxgiResource->GetSharedHandle(&sharedHandle))); + SafeRelease(dxgiResource); + + EGLint pBufferAttributes[] = {EGL_WIDTH, mWindowWidth, EGL_HEIGHT, + mWindowWidth, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_NONE}; + + mSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + sharedHandle, mConfig, pBufferAttributes); + ASSERT_TRUE(EGL_NO_SURFACE != mSurface); + } + + void makeCurrent() { ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)); } + + void TearDown() override + { + SafeRelease(mOffscreenSurfaceD3D11Texture); + + if (mDisplay != EGL_NO_DISPLAY) + { + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (mSurface != EGL_NO_SURFACE) + { + eglDestroySurface(mDisplay, mSurface); + mSurface = EGL_NO_SURFACE; + } + + if (mContext != EGL_NO_CONTEXT) + { + eglDestroyContext(mDisplay, mContext); + mContext = EGL_NO_CONTEXT; + } + + eglTerminate(mDisplay); + mDisplay = EGL_NO_DISPLAY; + } + + mOSWindow->destroy(); + SafeDelete(mOSWindow); + } + + void drawQuadUsingGL() + { + GLuint m2DProgram; + GLint mTexture2DUniformLocation; + + const std::string vertexShaderSource = + SHADER_SOURCE(precision highp float; attribute vec4 position; varying vec2 texcoord; + + void main() + { + gl_Position = vec4(position.xy, 0.0, 1.0); + texcoord = (position.xy * 0.5) + 0.5; + }); + + const std::string fragmentShaderSource2D = + SHADER_SOURCE(precision highp float; uniform sampler2D tex; varying vec2 texcoord; + + void main() + { + gl_FragColor = texture2D(tex, texcoord); + }); + + m2DProgram = CompileProgram(vertexShaderSource, fragmentShaderSource2D); + mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex"); + + uint8_t textureInitData[16] = { + 255, 0, 0, 255, // Red + 0, 255, 0, 255, // Green + 0, 0, 255, 255, // Blue + 255, 255, 0, 255 // Red + Green + }; + + // Create a simple RGBA texture + GLuint tex = 0; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, + textureInitData); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ASSERT_GL_NO_ERROR(); + + // Draw a quad using the texture + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(m2DProgram); + glUniform1i(mTexture2DUniformLocation, 0); + + GLint positionLocation = glGetAttribLocation(m2DProgram, "position"); + glUseProgram(m2DProgram); + const GLfloat vertices[] = + { + -1.0f, 1.0f, 0.5f, + -1.0f, -1.0f, 0.5f, + 1.0f, -1.0f, 0.5f, + -1.0f, 1.0f, 0.5f, + 1.0f, -1.0f, 0.5f, + 1.0f, 1.0f, 0.5f, + }; + + glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(positionLocation); + + glDrawArrays(GL_TRIANGLES, 0, 6); + ASSERT_GL_NO_ERROR(); + + glDeleteProgram(m2DProgram); + } + + void checkPixelsUsingGL() + { + // Note that the texture is in BGRA format + EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255); // Red + EXPECT_PIXEL_EQ(mWindowWidth - 1, 0, 0, 255, 0, 255); // Green + EXPECT_PIXEL_EQ(0, mWindowWidth - 1, 0, 0, 255, 255); // Blue + EXPECT_PIXEL_EQ(mWindowWidth - 1, mWindowWidth - 1, 255, 255, 0, 255); // Red + green + } + + void checkPixelsUsingD3D(bool usingPresentPathFast) + { + ASSERT_NE(nullptr, mOffscreenSurfaceD3D11Texture); + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + ID3D11Device *device; + ID3D11DeviceContext *context; + mOffscreenSurfaceD3D11Texture->GetDesc(&textureDesc); + mOffscreenSurfaceD3D11Texture->GetDevice(&device); + device->GetImmediateContext(&context); + ASSERT_NE(nullptr, device); + ASSERT_NE(nullptr, context); + + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + textureDesc.Usage = D3D11_USAGE_STAGING; + textureDesc.BindFlags = 0; + textureDesc.MiscFlags = 0; + ID3D11Texture2D *cpuTexture = nullptr; + ASSERT_TRUE(SUCCEEDED(device->CreateTexture2D(&textureDesc, nullptr, &cpuTexture))); + + context->CopyResource(cpuTexture, mOffscreenSurfaceD3D11Texture); + + D3D11_MAPPED_SUBRESOURCE mappedSubresource; + context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource); + ASSERT_EQ(static_cast<UINT>(mWindowWidth * 4), mappedSubresource.RowPitch); + ASSERT_EQ(static_cast<UINT>(mWindowWidth * mWindowWidth * 4), mappedSubresource.DepthPitch); + + angle::GLColor *byteData = reinterpret_cast<angle::GLColor *>(mappedSubresource.pData); + + // Note that the texture is in BGRA format, although the GLColor struct is RGBA + GLColor expectedTopLeftPixel = GLColor(0, 0, 255, 255); // Red + GLColor expectedTopRightPixel = GLColor(0, 255, 0, 255); // Green + GLColor expectedBottomLeftPixel = GLColor(255, 0, 0, 255); // Blue + GLColor expectedBottomRightPixel = GLColor(0, 255, 255, 255); // Red + Green + + if (usingPresentPathFast) + { + // Invert the expected values + GLColor tempTopLeft = expectedTopLeftPixel; + GLColor tempTopRight = expectedTopRightPixel; + expectedTopLeftPixel = expectedBottomLeftPixel; + expectedTopRightPixel = expectedBottomRightPixel; + expectedBottomLeftPixel = tempTopLeft; + expectedBottomRightPixel = tempTopRight; + } + + EXPECT_EQ(expectedTopLeftPixel, byteData[0]); + EXPECT_EQ(expectedTopRightPixel, byteData[(mWindowWidth - 1)]); + EXPECT_EQ(expectedBottomLeftPixel, byteData[(mWindowWidth - 1) * mWindowWidth]); + EXPECT_EQ(expectedBottomRightPixel, + byteData[(mWindowWidth - 1) * mWindowWidth + (mWindowWidth - 1)]); + + context->Unmap(cpuTexture, 0); + SafeRelease(cpuTexture); + SafeRelease(device); + SafeRelease(context); + } + + EGLDisplay mDisplay; + EGLContext mContext; + EGLSurface mSurface; + ID3D11Texture2D *mOffscreenSurfaceD3D11Texture; + EGLConfig mConfig; + OSWindow *mOSWindow; + GLint mWindowWidth; +}; + +// Test that rendering basic content onto a window surface when present path fast +// is enabled works as expected +TEST_P(EGLPresentPathD3D11, WindowPresentPathFast) +{ + initializeEGL(true); + createWindowSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); +} + +// Test that rendering basic content onto a client buffer surface when present path fast +// works as expected, and is also oriented the correct way around +TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathFast) +{ + initializeEGL(true); + createPbufferFromClientBufferSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); + checkPixelsUsingD3D(true); +} + +// Test that rendering basic content onto a window surface when present path fast +// is disabled works as expected +TEST_P(EGLPresentPathD3D11, WindowPresentPathCopy) +{ + initializeEGL(false); + createWindowSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); +} + +// Test that rendering basic content onto a client buffer surface when present path +// fast is disabled works as expected, and is also oriented the correct way around +TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathCopy) +{ + initializeEGL(false); + createPbufferFromClientBufferSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); + checkPixelsUsingD3D(false); +} + +ANGLE_INSTANTIATE_TEST(EGLPresentPathD3D11, ES2_D3D11(), ES2_D3D11_FL9_3());
\ No newline at end of file diff --git a/gfx/angle/src/tests/egl_tests/EGLQueryContextTest.cpp b/gfx/angle/src/tests/egl_tests/EGLQueryContextTest.cpp new file mode 100755 index 000000000..ff4a43f23 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLQueryContextTest.cpp @@ -0,0 +1,153 @@ +// +// Copyright (c) 2015 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. +// + +#include <gtest/gtest.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "test_utils/angle_test_configs.h" + +using namespace angle; + +class EGLQueryContextTest : public testing::TestWithParam<PlatformParameters> +{ + public: + void SetUp() override + { + int clientVersion = GetParam().majorVersion; + + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT")); + EXPECT_TRUE(eglGetPlatformDisplayEXT != NULL); + + EGLint dispattrs[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), + EGL_NONE + }; + mDisplay = eglGetPlatformDisplayEXT( + EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs); + EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY); + EXPECT_TRUE(eglInitialize(mDisplay, NULL, NULL) != EGL_FALSE); + + EGLint ncfg; + EGLint cfgattrs[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, clientVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + EXPECT_TRUE(eglChooseConfig(mDisplay, cfgattrs, &mConfig, 1, &ncfg) != EGL_FALSE); + EXPECT_TRUE(ncfg == 1); + + EGLint ctxattrs[] = + { + EGL_CONTEXT_CLIENT_VERSION, clientVersion, + EGL_NONE + }; + mContext = eglCreateContext(mDisplay, mConfig, NULL, ctxattrs); + EXPECT_TRUE(mContext != EGL_NO_CONTEXT); + + EGLint surfattrs[] = + { + EGL_WIDTH, 16, + EGL_HEIGHT, 16, + EGL_NONE + }; + mSurface = eglCreatePbufferSurface(mDisplay, mConfig, surfattrs); + EXPECT_TRUE(mSurface != EGL_NO_SURFACE); + } + + void TearDown() override + { + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(mDisplay, mContext); + eglDestroySurface(mDisplay, mSurface); + eglTerminate(mDisplay); + } + + EGLDisplay mDisplay; + EGLConfig mConfig; + EGLContext mContext; + EGLSurface mSurface; +}; + +TEST_P(EGLQueryContextTest, GetConfigID) +{ + EGLint configId, contextConfigId; + EXPECT_TRUE(eglGetConfigAttrib(mDisplay, mConfig, EGL_CONFIG_ID, &configId) != EGL_FALSE); + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_CONFIG_ID, &contextConfigId) != EGL_FALSE); + EXPECT_TRUE(configId == contextConfigId); +} + +TEST_P(EGLQueryContextTest, GetClientType) +{ + EGLint clientType; + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_CONTEXT_CLIENT_TYPE, &clientType) != EGL_FALSE); + EXPECT_TRUE(clientType == EGL_OPENGL_ES_API); +} + +TEST_P(EGLQueryContextTest, GetClientVersion) +{ + EGLint clientVersion; + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_CONTEXT_CLIENT_VERSION, &clientVersion) != EGL_FALSE); + EXPECT_TRUE(clientVersion == GetParam().majorVersion); +} + +TEST_P(EGLQueryContextTest, GetRenderBufferNoSurface) +{ + EGLint renderBuffer; + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_RENDER_BUFFER, &renderBuffer) != EGL_FALSE); + EXPECT_TRUE(renderBuffer == EGL_NONE); +} + +TEST_P(EGLQueryContextTest, GetRenderBufferBoundSurface) +{ + EGLint renderBuffer, contextRenderBuffer; + EXPECT_TRUE(eglQuerySurface(mDisplay, mSurface, EGL_RENDER_BUFFER, &renderBuffer) != EGL_FALSE); + EXPECT_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) != EGL_FALSE); + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_RENDER_BUFFER, &contextRenderBuffer) != EGL_FALSE); + EXPECT_TRUE(renderBuffer == contextRenderBuffer); +} + +TEST_P(EGLQueryContextTest, BadDisplay) +{ + EGLint val; + EXPECT_TRUE(eglQueryContext(EGL_NO_DISPLAY, mContext, EGL_CONTEXT_CLIENT_TYPE, &val) == EGL_FALSE); + EXPECT_TRUE(eglGetError() == EGL_BAD_DISPLAY); +} + +TEST_P(EGLQueryContextTest, NotInitialized) +{ + EGLint val; + TearDown(); + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_CONTEXT_CLIENT_TYPE, &val) == EGL_FALSE); + EXPECT_TRUE(eglGetError() == EGL_NOT_INITIALIZED); + + mDisplay = EGL_NO_DISPLAY; + mSurface = EGL_NO_SURFACE; + mContext = EGL_NO_CONTEXT; +} + +TEST_P(EGLQueryContextTest, BadContext) +{ + EGLint val; + EXPECT_TRUE(eglQueryContext(mDisplay, EGL_NO_CONTEXT, EGL_CONTEXT_CLIENT_TYPE, &val) == EGL_FALSE); + EXPECT_TRUE(eglGetError() == EGL_BAD_CONTEXT); +} + +TEST_P(EGLQueryContextTest, BadAttribute) +{ + EGLint val; + EXPECT_TRUE(eglQueryContext(mDisplay, mContext, EGL_HEIGHT, &val) == EGL_FALSE); + EXPECT_TRUE(eglGetError() == EGL_BAD_ATTRIBUTE); +} + +ANGLE_INSTANTIATE_TEST(EGLQueryContextTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3(), ES2_OPENGL(), + ES3_D3D11(), ES3_OPENGL()); diff --git a/gfx/angle/src/tests/egl_tests/EGLRobustnessTest.cpp b/gfx/angle/src/tests/egl_tests/EGLRobustnessTest.cpp new file mode 100755 index 000000000..0482a7fe5 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLRobustnessTest.cpp @@ -0,0 +1,234 @@ +// +// 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. +// + +// EGLRobustnessTest.cpp: tests for EGL_EXT_create_context_robustness + +#include <gtest/gtest.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "OSWindow.h" +#include "test_utils/ANGLETest.h" + +using namespace angle; + +class EGLRobustnessTest : public ::testing::TestWithParam<angle::PlatformParameters> +{ + public: + void SetUp() override + { + mOSWindow = CreateOSWindow(); + mOSWindow->initialize("EGLRobustnessTest", 500, 500); + mOSWindow->setVisible(true); + + auto eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + + const auto &platform = GetParam().eglParameters; + + std::vector<EGLint> displayAttributes; + displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); + displayAttributes.push_back(platform.renderer); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE); + displayAttributes.push_back(platform.majorVersion); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE); + displayAttributes.push_back(platform.minorVersion); + + if (platform.deviceType != EGL_DONT_CARE) + { + displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE); + displayAttributes.push_back(platform.deviceType); + } + + displayAttributes.push_back(EGL_NONE); + + mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, + reinterpret_cast<void *>(mOSWindow->getNativeDisplay()), + &displayAttributes[0]); + ASSERT_NE(EGL_NO_DISPLAY, mDisplay); + + ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE); + + const char *extensions = eglQueryString(mDisplay, EGL_EXTENSIONS); + if (strstr(extensions, "EGL_EXT_create_context_robustness") == nullptr) + { + std::cout << "Test skipped due to missing EGL_EXT_create_context_robustness" + << std::endl; + return; + } + + int nConfigs = 0; + ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE); + ASSERT_LE(1, nConfigs); + + int nReturnedConfigs = 0; + ASSERT_TRUE(eglGetConfigs(mDisplay, &mConfig, 1, &nReturnedConfigs) == EGL_TRUE); + ASSERT_EQ(1, nReturnedConfigs); + + mWindow = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr); + ASSERT_EGL_SUCCESS(); + + mInitialized = true; + } + + void TearDown() override + { + eglDestroySurface(mDisplay, mWindow); + eglDestroyContext(mDisplay, mContext); + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(mDisplay); + EXPECT_EGL_SUCCESS(); + + SafeDelete(mOSWindow); + } + + void createContext(EGLint resetStrategy) + { + const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, + resetStrategy, EGL_NONE}; + mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs); + ASSERT_NE(EGL_NO_CONTEXT, mContext); + + eglMakeCurrent(mDisplay, mWindow, mWindow, mContext); + ASSERT_EGL_SUCCESS(); + + const char *extensionString = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); + ASSERT_NE(nullptr, strstr(extensionString, "GL_ANGLE_instanced_arrays")); + + mDrawElementsInstancedANGLE = + (PFNGLDRAWELEMENTSINSTANCEDANGLEPROC)eglGetProcAddress("glDrawElementsInstancedANGLE"); + ASSERT_NE(nullptr, mDrawElementsInstancedANGLE); + } + + void forceContextReset() + { + // Cause a GPU reset by drawing 100,000,000 fullscreen quads + GLuint program = CompileProgram( + "attribute vec4 pos;\n" + "void main() {gl_Position = pos;}\n", + "precision mediump float;\n" + "void main() {gl_FragColor = vec4(1.0);}\n"); + ASSERT_NE(0u, program); + glUseProgram(program); + + GLfloat vertices[] = { + -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + }; + + const int kNumQuads = 10000; + std::vector<GLushort> indices(6 * kNumQuads); + + for (size_t i = 0; i < kNumQuads; i++) + { + indices[i * 6 + 0] = 0; + indices[i * 6 + 1] = 1; + indices[i * 6 + 2] = 2; + indices[i * 6 + 3] = 1; + indices[i * 6 + 4] = 2; + indices[i * 6 + 5] = 3; + } + + glBindAttribLocation(program, 0, "pos"); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(0); + + glViewport(0, 0, mOSWindow->getWidth(), mOSWindow->getHeight()); + glClearColor(1.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + mDrawElementsInstancedANGLE(GL_TRIANGLES, kNumQuads * 6, GL_UNSIGNED_SHORT, indices.data(), + 10000); + + glFinish(); + } + + protected: + EGLDisplay mDisplay = EGL_NO_DISPLAY; + EGLSurface mWindow = EGL_NO_SURFACE; + bool mInitialized = false; + PFNGLDRAWELEMENTSINSTANCEDANGLEPROC mDrawElementsInstancedANGLE = nullptr; + + private: + EGLContext mContext = EGL_NO_CONTEXT; + EGLConfig mConfig = 0; + OSWindow *mOSWindow = nullptr; +}; + +// Check glGetGraphicsResetStatusEXT returns GL_NO_ERROR if we did nothing +TEST_P(EGLRobustnessTest, NoErrorByDefault) +{ + if (!mInitialized) + { + return; + } + ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR); +} + +// Checks that the application gets no loss with NO_RESET_NOTIFICATION +TEST_P(EGLRobustnessTest, DISABLED_NoResetNotification) +{ + if (!mInitialized) + { + return; + } + + createContext(EGL_NO_RESET_NOTIFICATION_EXT); + + if (!IsWindows()) + { + std::cout << "Test disabled on non Windows platforms because drivers can't recover. " + << "See " << __FILE__ << ":" << __LINE__ << std::endl; + return; + } + std::cout << "Causing a GPU reset, brace for impact." << std::endl; + + forceContextReset(); + ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR); +} + +// Checks that resetting the ANGLE display allows to get rid of the context loss. +// Also checks that the application gets notified of the loss of the display. +// We coalesce both tests to reduce the number of TDRs done on Windows: by default +// having more than 5 TDRs in a minute will cause Windows to disable the GPU until +// the computer is rebooted. +TEST_P(EGLRobustnessTest, DISABLED_ResettingDisplayWorks) +{ + if (!mInitialized) + { + return; + } + + createContext(EGL_LOSE_CONTEXT_ON_RESET_EXT); + + if (!IsWindows()) + { + std::cout << "Test disabled on non Windows platforms because drivers can't recover. " + << "See " << __FILE__ << ":" << __LINE__ << std::endl; + return; + } + std::cout << "Causing a GPU reset, brace for impact." << std::endl; + + forceContextReset(); + ASSERT_TRUE(glGetGraphicsResetStatusEXT() != GL_NO_ERROR); + + TearDown(); + SetUp(); + ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR); +} + +// Tests causing GPU resets are disabled, use the following args to run them: +// --gtest_also_run_disabled_tests --gtest_filter=EGLRobustnessTest\* + +// Note that on Windows the OpenGL driver fails hard (popup that closes the application) +// if there was a TDR caused by D3D so we don't run D3D tests at the same time as the OpenGL tests. +#define D3D_HAS_PRIORITY 1 +#if D3D_HAS_PRIORITY && (defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)) +ANGLE_INSTANTIATE_TEST(EGLRobustnessTest, ES2_D3D9(), ES2_D3D11()); +#else +ANGLE_INSTANTIATE_TEST(EGLRobustnessTest, ES2_OPENGL()); +#endif diff --git a/gfx/angle/src/tests/egl_tests/EGLSanityCheckTest.cpp b/gfx/angle/src/tests/egl_tests/EGLSanityCheckTest.cpp new file mode 100755 index 000000000..b92f9bc16 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLSanityCheckTest.cpp @@ -0,0 +1,30 @@ +// +// Copyright 2015 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. +// + +// EGLSanityCheckTest.cpp: +// tests used to check setup in which tests are run. + +#include <gtest/gtest.h> + +#include "test_utils/ANGLETest.h" + +// Checks the tests are running against ANGLE +TEST(EGLSanityCheckTest, IsRunningOnANGLE) +{ + const char *extensionString = + static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); + ASSERT_NE(strstr(extensionString, "EGL_ANGLE_platform_angle"), nullptr); +} + +// Checks that getting function pointer works +TEST(EGLSanityCheckTest, HasGetPlatformDisplayEXT) +{ + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + + ASSERT_NE(eglGetPlatformDisplayEXT, nullptr); +} diff --git a/gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp b/gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp new file mode 100755 index 000000000..b667cf778 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp @@ -0,0 +1,547 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// EGLStreamTest: +// Tests pertaining to egl::Stream. +// + +#include <gtest/gtest.h> + +#include <vector> + +#include "media/yuvtest.inl" +#include "OSWindow.h" +#include "test_utils/ANGLETest.h" + +using namespace angle; + +namespace +{ + +class EGLStreamTest : public ANGLETest +{ + protected: + EGLStreamTest() + { + setWindowWidth(128); + setWindowHeight(128); + setConfigRedBits(8); + setConfigGreenBits(8); + setConfigBlueBits(8); + setConfigAlphaBits(8); + setConfigDepthBits(24); + } +}; + +// Tests validation of the stream API +TEST_P(EGLStreamTest, StreamValidationTest) +{ + EGLWindow *window = getEGLWindow(); + EGLDisplay display = window->getDisplay(); + const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_KHR_stream") == nullptr) + { + std::cout << "Stream extension not supported" << std::endl; + return; + } + + const EGLint streamAttributesBad[] = { + EGL_STREAM_STATE_KHR, + 0, + EGL_NONE, + EGL_PRODUCER_FRAME_KHR, + 0, + EGL_NONE, + EGL_CONSUMER_FRAME_KHR, + 0, + EGL_NONE, + EGL_CONSUMER_LATENCY_USEC_KHR, + -1, + EGL_NONE, + EGL_RED_SIZE, + EGL_DONT_CARE, + EGL_NONE, + }; + + // Validate create stream attributes + EGLStreamKHR stream = eglCreateStreamKHR(display, &streamAttributesBad[0]); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + ASSERT_EQ(EGL_NO_STREAM_KHR, stream); + + stream = eglCreateStreamKHR(display, &streamAttributesBad[3]); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + ASSERT_EQ(EGL_NO_STREAM_KHR, stream); + + stream = eglCreateStreamKHR(display, &streamAttributesBad[6]); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + ASSERT_EQ(EGL_NO_STREAM_KHR, stream); + + stream = eglCreateStreamKHR(display, &streamAttributesBad[9]); + ASSERT_EGL_ERROR(EGL_BAD_PARAMETER); + ASSERT_EQ(EGL_NO_STREAM_KHR, stream); + + stream = eglCreateStreamKHR(display, &streamAttributesBad[12]); + ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE); + ASSERT_EQ(EGL_NO_STREAM_KHR, stream); + + const EGLint streamAttributes[] = { + EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_NONE, + }; + + stream = eglCreateStreamKHR(EGL_NO_DISPLAY, streamAttributes); + ASSERT_EGL_ERROR(EGL_BAD_DISPLAY); + ASSERT_EQ(EGL_NO_STREAM_KHR, stream); + + // Create an actual stream + stream = eglCreateStreamKHR(display, streamAttributes); + ASSERT_EGL_SUCCESS(); + ASSERT_NE(EGL_NO_STREAM_KHR, stream); + + // Assert it is in the created state + EGLint state; + eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(EGL_STREAM_STATE_CREATED_KHR, state); + + // Test getting and setting the latency + EGLint latency = 10; + eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, latency); + ASSERT_EGL_SUCCESS(); + eglQueryStreamKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, &latency); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(10, latency); + eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, -1); + ASSERT_EGL_ERROR(EGL_BAD_PARAMETER); + ASSERT_EQ(10, latency); + + // Test the 64-bit queries + EGLuint64KHR value; + eglQueryStreamu64KHR(display, stream, EGL_CONSUMER_FRAME_KHR, &value); + ASSERT_EGL_SUCCESS(); + eglQueryStreamu64KHR(display, stream, EGL_PRODUCER_FRAME_KHR, &value); + ASSERT_EGL_SUCCESS(); + + // Destroy the stream + eglDestroyStreamKHR(display, stream); + ASSERT_EGL_SUCCESS(); +} + +// Tests validation of stream consumer gltexture API +TEST_P(EGLStreamTest, StreamConsumerGLTextureValidationTest) +{ + EGLWindow *window = getEGLWindow(); + EGLDisplay display = window->getDisplay(); + const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_KHR_stream_consumer_gltexture") == nullptr) + { + std::cout << "Stream consumer gltexture extension not supported" << std::endl; + return; + } + + const EGLint streamAttributes[] = { + EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE, + }; + + EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes); + ASSERT_EGL_SUCCESS(); + + EGLBoolean result = eglStreamConsumerGLTextureExternalKHR(display, stream); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); + result = eglStreamConsumerGLTextureExternalKHR(display, stream); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + EGLint state; + eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state); + + eglDestroyStreamKHR(display, stream); + ASSERT_EGL_SUCCESS(); +} + +// Tests validation of stream consumer gltexture yuv API +TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVValidationTest) +{ + EGLWindow *window = getEGLWindow(); + EGLDisplay display = window->getDisplay(); + const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_NV_stream_consumer_gltexture_yuv") == nullptr) + { + std::cout << "Stream consumer gltexture yuv extension not supported" << std::endl; + return; + } + + const EGLint streamAttributes[] = { + EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE, + }; + + EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes); + ASSERT_EGL_SUCCESS(); + + EGLAttrib consumerAttributesBad[] = { + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, // 0 + EGL_YUV_NUMBER_OF_PLANES_EXT, + 0, + EGL_NONE, + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, // 5 + EGL_YUV_NUMBER_OF_PLANES_EXT, + 1, + EGL_NONE, + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, // 10 + EGL_YUV_NUMBER_OF_PLANES_EXT, + 1, + EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 9999, + EGL_NONE, + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, // 17 + EGL_YUV_NUMBER_OF_PLANES_EXT, + 1, + EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 0, + EGL_YUV_PLANE1_TEXTURE_UNIT_NV, + 1, + EGL_NONE, + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, // 26 + EGL_YUV_NUMBER_OF_PLANES_EXT, + 2, + EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 0, + EGL_YUV_PLANE1_TEXTURE_UNIT_NV, + 0, + EGL_NONE, + }; + + EGLAttrib consumerAttributes[] = { + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, + EGL_YUV_NUMBER_OF_PLANES_EXT, + 2, + EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 0, + EGL_YUV_PLANE1_TEXTURE_UNIT_NV, + 1, + EGL_NONE, + }; + + EGLBoolean result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[0]); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_MATCH); + + result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[5]); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_MATCH); + + result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[10]); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + + result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[17]); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_MATCH); + + result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + + GLuint tex[2]; + glGenTextures(2, tex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]); + + result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[26]); + ASSERT_EGL_FALSE(result); + ASSERT_EGL_ERROR(EGL_BAD_ACCESS); + + result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + EGLint state; + eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state); + + eglDestroyStreamKHR(display, stream); + ASSERT_EGL_SUCCESS(); +} + +// Tests that deleting a texture invalidates the associated stream +TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVDeletionTest) +{ + EGLWindow *window = getEGLWindow(); + EGLDisplay display = window->getDisplay(); + const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_ANGLE_stream_producer_d3d_texture_nv12") == nullptr) + { + std::cout << "Stream producer d3d nv12 texture not supported" << std::endl; + return; + } + + const EGLint streamAttributes[] = { + EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE, + }; + + EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes); + ASSERT_EGL_SUCCESS(); + + EGLAttrib consumerAttributes[] = { + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, + EGL_YUV_NUMBER_OF_PLANES_EXT, + 2, + EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 0, + EGL_YUV_PLANE1_TEXTURE_UNIT_NV, + 1, + EGL_NONE, + }; + + GLuint tex[2]; + glGenTextures(2, tex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]); + + EGLBoolean result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + EGLAttrib producerAttributes[] = { + EGL_NONE, + }; + + result = eglCreateStreamProducerD3DTextureNV12ANGLE(display, stream, producerAttributes); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + EGLint state; + eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(EGL_STREAM_STATE_EMPTY_KHR, state); + + // Delete the first texture, which should be enough to invalidate the stream + glDeleteTextures(1, tex); + + eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(EGL_STREAM_STATE_DISCONNECTED_KHR, state); + + eglDestroyStreamKHR(display, stream); + ASSERT_EGL_SUCCESS(); +} + +// End2end test for rendering an NV12 texture. Renders a YUV quad, reads back the RGB values, and +// ensures they are correct +TEST_P(EGLStreamTest, StreamProducerTextureNV12End2End) +{ + EGLWindow *window = getEGLWindow(); + EGLDisplay display = window->getDisplay(); + if (!eglDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture_nv12")) + { + std::cout << "Stream producer d3d nv12 texture not supported" << std::endl; + return; + } + + bool useESSL3Shaders = + getClientMajorVersion() >= 3 && extensionEnabled("GL_OES_EGL_image_external_essl3"); + + // yuv to rgb conversion shader using Microsoft's given conversion formulas + std::string yuvVS, yuvPS; + if (useESSL3Shaders) + { + yuvVS = + "#version 300 es\n" + "in highp vec4 position;\n" + "out vec2 texcoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = position;\n" + " texcoord = (position.xy * 0.5) + 0.5;\n" + " texcoord.y = 1.0 - texcoord.y;\n" + "}\n"; + yuvPS = + "#version 300 es\n" + "#extension GL_OES_EGL_image_external_essl3 : require\n" + "#extension GL_NV_EGL_stream_consumer_external : require\n" + "precision highp float;\n" + "in vec2 texcoord;\n" + "out vec4 color;\n" + "uniform samplerExternalOES y;\n" + "uniform samplerExternalOES uv\n;" + "void main(void)\n" + "{\n" + " float c = texture(y, texcoord).r - (16.0 / 256.0);\n" + " float d = texture(uv, texcoord).r - 0.5;\n" + " float e = texture(uv, texcoord).g - 0.5;\n" + " float r = 1.164383 * c + 1.596027 * e;\n" + " float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n" + " float b = 1.164383 * c + 2.017232 * d;\n" + " color = vec4(r, g, b, 1.0);\n" + "}\n"; + } + else + { + yuvVS = + "attribute highp vec4 position;\n" + "varying vec2 texcoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = position;\n" + " texcoord = (position.xy * 0.5) + 0.5;\n" + " texcoord.y = 1.0 - texcoord.y;\n" + "}\n"; + + yuvPS = + "#extension GL_NV_EGL_stream_consumer_external : require\n" + "precision highp float;\n" + "varying vec2 texcoord;\n" + "uniform samplerExternalOES y;\n" + "uniform samplerExternalOES uv\n;" + "void main(void)\n" + "{\n" + " float c = texture2D(y, texcoord).r - (16.0 / 256.0);\n" + " float d = texture2D(uv, texcoord).r - 0.5;\n" + " float e = texture2D(uv, texcoord).g - 0.5;\n" + " float r = 1.164383 * c + 1.596027 * e;\n" + " float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n" + " float b = 1.164383 * c + 2.017232 * d;\n" + " gl_FragColor = vec4(r, g, b, 1.0);\n" + "}\n"; + } + + GLuint program = CompileProgram(yuvVS, yuvPS); + ASSERT_NE(0u, program); + GLuint yUniform = glGetUniformLocation(program, "y"); + GLuint uvUniform = glGetUniformLocation(program, "uv"); + + // Fetch the D3D11 device + EGLDeviceEXT eglDevice; + eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, (EGLAttrib *)&eglDevice); + ID3D11Device *device; + eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, (EGLAttrib *)&device); + + // Create the NV12 D3D11 texture + HRESULT res; + D3D11_TEXTURE2D_DESC desc; + desc.Width = yuvtest_width; + desc.Height = yuvtest_height; + desc.Format = DXGI_FORMAT_NV12; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA subres; + subres.pSysMem = yuvtest_data; + subres.SysMemPitch = yuvtest_width; + subres.SysMemSlicePitch = yuvtest_width * yuvtest_height * 3 / 2; + + ID3D11Texture2D *texture = nullptr; + res = device->CreateTexture2D(&desc, &subres, &texture); + + // Create the stream + const EGLint streamAttributes[] = { + EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE, + }; + + EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes); + ASSERT_EGL_SUCCESS(); + + EGLAttrib consumerAttributes[] = { + EGL_COLOR_BUFFER_TYPE, + EGL_YUV_BUFFER_EXT, + EGL_YUV_NUMBER_OF_PLANES_EXT, + 2, + EGL_YUV_PLANE0_TEXTURE_UNIT_NV, + 0, + EGL_YUV_PLANE1_TEXTURE_UNIT_NV, + 1, + EGL_NONE, + }; + + GLuint tex[2]; + glGenTextures(2, tex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ASSERT_GL_NO_ERROR(); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ASSERT_GL_NO_ERROR(); + + EGLBoolean result = + eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + EGLAttrib producerAttributes[] = { + EGL_NONE, + }; + + result = eglCreateStreamProducerD3DTextureNV12ANGLE(display, stream, producerAttributes); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + // Insert the frame + EGLAttrib frameAttributes[] = { + EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0, EGL_NONE, + }; + result = eglStreamPostD3DTextureNV12ANGLE(display, stream, (void *)texture, frameAttributes); + ASSERT_EGL_TRUE(result); + ASSERT_EGL_SUCCESS(); + + EGLint state; + eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR, state); + + eglStreamConsumerAcquireKHR(display, stream); + ASSERT_EGL_SUCCESS(); + + glUseProgram(program); + glUniform1i(yUniform, 0); + glUniform1i(uvUniform, 1); + drawQuad(program, "position", 0.0f); + ASSERT_GL_NO_ERROR(); + + eglStreamConsumerReleaseKHR(display, stream); + ASSERT_EGL_SUCCESS(); + + eglSwapBuffers(display, window->getSurface()); + SafeRelease(texture); +} + +ANGLE_INSTANTIATE_TEST(EGLStreamTest, + ES2_D3D9(), + ES2_D3D11(), + ES3_D3D11(), + ES2_OPENGL(), + ES3_OPENGL()); +} // anonymous namespace diff --git a/gfx/angle/src/tests/egl_tests/EGLSurfaceTest.cpp b/gfx/angle/src/tests/egl_tests/EGLSurfaceTest.cpp new file mode 100755 index 000000000..513b01d44 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLSurfaceTest.cpp @@ -0,0 +1,517 @@ +// +// Copyright 2015 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. +// +// EGLSurfaceTest: +// Tests pertaining to egl::Surface. +// + +#include <gtest/gtest.h> + +#include <vector> + +#include "OSWindow.h" +#include "test_utils/ANGLETest.h" + +namespace +{ + +class EGLSurfaceTest : public testing::Test +{ + protected: + EGLSurfaceTest() + : mDisplay(EGL_NO_DISPLAY), + mWindowSurface(EGL_NO_SURFACE), + mPbufferSurface(EGL_NO_SURFACE), + mContext(EGL_NO_CONTEXT), + mSecondContext(EGL_NO_CONTEXT), + mOSWindow(nullptr) + { + } + + void SetUp() override + { + mOSWindow = CreateOSWindow(); + mOSWindow->initialize("EGLSurfaceTest", 64, 64); + } + + // Release any resources created in the test body + void TearDown() override + { + if (mDisplay != EGL_NO_DISPLAY) + { + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (mWindowSurface != EGL_NO_SURFACE) + { + eglDestroySurface(mDisplay, mWindowSurface); + mWindowSurface = EGL_NO_SURFACE; + } + + if (mPbufferSurface != EGL_NO_SURFACE) + { + eglDestroySurface(mDisplay, mPbufferSurface); + mPbufferSurface = EGL_NO_SURFACE; + } + + if (mContext != EGL_NO_CONTEXT) + { + eglDestroyContext(mDisplay, mContext); + mContext = EGL_NO_CONTEXT; + } + + if (mSecondContext != EGL_NO_CONTEXT) + { + eglDestroyContext(mDisplay, mSecondContext); + mSecondContext = EGL_NO_CONTEXT; + } + + eglTerminate(mDisplay); + mDisplay = EGL_NO_DISPLAY; + } + + mOSWindow->destroy(); + SafeDelete(mOSWindow); + + ASSERT_TRUE(mWindowSurface == EGL_NO_SURFACE && mContext == EGL_NO_CONTEXT); + } + + void initializeDisplay(EGLenum platformType) + { + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT")); + ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr); + + std::vector<EGLint> displayAttributes; + displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); + displayAttributes.push_back(platformType); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE); + displayAttributes.push_back(EGL_DONT_CARE); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE); + displayAttributes.push_back(EGL_DONT_CARE); + + if (platformType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE || platformType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE); + displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + } + displayAttributes.push_back(EGL_NONE); + + mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, + reinterpret_cast<void *>(mOSWindow->getNativeDisplay()), + displayAttributes.data()); + ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); + + EGLint majorVersion, minorVersion; + ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE); + + eglBindAPI(EGL_OPENGL_ES_API); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + } + + void initializeSurface(EGLConfig config) + { + mConfig = config; + + std::vector<EGLint> surfaceAttributes; + surfaceAttributes.push_back(EGL_NONE); + surfaceAttributes.push_back(EGL_NONE); + + // Create first window surface + mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), &surfaceAttributes[0]); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + mPbufferSurface = eglCreatePbufferSurface(mDisplay, mConfig, &surfaceAttributes[0]); + + EGLint contextAttibutes[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + mSecondContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + } + + void initializeSurfaceWithDefaultConfig() + { + const EGLint configAttributes[] = + { + EGL_RED_SIZE, EGL_DONT_CARE, + EGL_GREEN_SIZE, EGL_DONT_CARE, + EGL_BLUE_SIZE, EGL_DONT_CARE, + EGL_ALPHA_SIZE, EGL_DONT_CARE, + EGL_DEPTH_SIZE, EGL_DONT_CARE, + EGL_STENCIL_SIZE, EGL_DONT_CARE, + EGL_SAMPLE_BUFFERS, 0, + EGL_NONE + }; + + EGLint configCount; + EGLConfig config; + ASSERT_TRUE(eglChooseConfig(mDisplay, configAttributes, &config, 1, &configCount) || (configCount != 1) == EGL_TRUE); + + initializeSurface(config); + } + + GLuint createProgram() + { + const std::string testVertexShaderSource = SHADER_SOURCE + ( + attribute highp vec4 position; + + void main(void) + { + gl_Position = position; + } + ); + + const std::string testFragmentShaderSource = SHADER_SOURCE + ( + void main(void) + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + ); + + return CompileProgram(testVertexShaderSource, testFragmentShaderSource); + } + + void drawWithProgram(GLuint program) + { + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + GLint positionLocation = glGetAttribLocation(program, "position"); + + glUseProgram(program); + + const GLfloat vertices[] = + { + -1.0f, 1.0f, 0.5f, + -1.0f, -1.0f, 0.5f, + 1.0f, -1.0f, 0.5f, + + -1.0f, 1.0f, 0.5f, + 1.0f, -1.0f, 0.5f, + 1.0f, 1.0f, 0.5f, + }; + + glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(positionLocation); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableVertexAttribArray(positionLocation); + glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL); + + EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255); + } + + void runMessageLoopTest(EGLSurface secondSurface, EGLContext secondContext) + { + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + // Make a second context current + eglMakeCurrent(mDisplay, secondSurface, secondSurface, secondContext); + eglDestroySurface(mDisplay, mWindowSurface); + + // Create second window surface + std::vector<EGLint> surfaceAttributes; + surfaceAttributes.push_back(EGL_NONE); + surfaceAttributes.push_back(EGL_NONE); + + mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), &surfaceAttributes[0]); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + mOSWindow->signalTestEvent(); + mOSWindow->messageLoop(); + ASSERT_TRUE(mOSWindow->didTestEventFire()); + + // Simple operation to test the FBO is set appropriately + glClear(GL_COLOR_BUFFER_BIT); + } + + EGLDisplay mDisplay; + EGLSurface mWindowSurface; + EGLSurface mPbufferSurface; + EGLContext mContext; + EGLContext mSecondContext; + EGLConfig mConfig; + OSWindow *mOSWindow; +}; + +// Test a surface bug where we could have two Window surfaces active +// at one time, blocking message loops. See http://crbug.com/475085 +TEST_F(EGLSurfaceTest, MessageLoopBug) +{ + const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + initializeSurfaceWithDefaultConfig(); + + runMessageLoopTest(EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +// Tests the message loop bug, but with setting a second context +// instead of null. +TEST_F(EGLSurfaceTest, MessageLoopBugContext) +{ + const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + initializeSurfaceWithDefaultConfig(); + + runMessageLoopTest(mPbufferSurface, mSecondContext); +} + +// Test a bug where calling makeCurrent twice would release the surface +TEST_F(EGLSurfaceTest, MakeCurrentTwice) +{ +#if defined(ANGLE_PLATFORM_APPLE) && !defined(ANGLE_STANDALONE_BUILD) + // TODO(cwallez) Make context creation return at least an OpenGL ES 2 context on + // the Mac trybots. + std::cout << "Test skipped temporarily skipped on the Mac trybots" << std::endl; + return; +#endif + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + initializeSurfaceWithDefaultConfig(); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_TRUE(eglGetError() == EGL_SUCCESS); + + // Simple operation to test the FBO is set appropriately + glClear(GL_COLOR_BUFFER_BIT); +} + +// Test that the D3D window surface is correctly resized after calling swapBuffers +TEST_F(EGLSurfaceTest, ResizeD3DWindow) +{ + const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + initializeSurfaceWithDefaultConfig(); + + eglSwapBuffers(mDisplay, mWindowSurface); + ASSERT_EGL_SUCCESS(); + + EGLint height; + eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(64, height); // initial size + + // set window's height to 0 + mOSWindow->resize(64, 0); + + eglSwapBuffers(mDisplay, mWindowSurface); + ASSERT_EGL_SUCCESS(); + + eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(0, height); + + // restore window's height + mOSWindow->resize(64, 64); + + eglSwapBuffers(mDisplay, mWindowSurface); + ASSERT_EGL_SUCCESS(); + + eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height); + ASSERT_EGL_SUCCESS(); + ASSERT_EQ(64, height); +} + +// Test creating a surface that supports a EGLConfig with 16bit +// support GL_RGB565 +TEST_F(EGLSurfaceTest, CreateWithEGLConfig5650Support) +{ + if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d")) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + const EGLint configAttributes[] = + { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLE_BUFFERS, 0, + EGL_NONE + }; + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + EGLConfig config; + if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE) + { + std::cout << "EGLConfig for a GL_RGB565 surface is not supported, skipping test" << std::endl; + return; + } + + initializeSurface(config); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_EGL_SUCCESS(); + + GLuint program = createProgram(); + ASSERT_NE(0u, program); + drawWithProgram(program); + EXPECT_GL_NO_ERROR(); + glDeleteProgram(program); +} + +// Test creating a surface that supports a EGLConfig with 16bit +// support GL_RGBA4 +TEST_F(EGLSurfaceTest, CreateWithEGLConfig4444Support) +{ + if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d")) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + const EGLint configAttributes[] = + { + EGL_RED_SIZE, 4, + EGL_GREEN_SIZE, 4, + EGL_BLUE_SIZE, 4, + EGL_ALPHA_SIZE, 4, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLE_BUFFERS, 0, + EGL_NONE + }; + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + EGLConfig config; + if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE) + { + std::cout << "EGLConfig for a GL_RGBA4 surface is not supported, skipping test" << std::endl; + return; + } + + initializeSurface(config); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_EGL_SUCCESS(); + + GLuint program = createProgram(); + ASSERT_NE(0u, program); + drawWithProgram(program); + EXPECT_GL_NO_ERROR(); + glDeleteProgram(program); +} + +// Test creating a surface that supports a EGLConfig with 16bit +// support GL_RGB5_A1 +TEST_F(EGLSurfaceTest, CreateWithEGLConfig5551Support) +{ + if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d")) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + const EGLint configAttributes[] = + { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 5, + EGL_BLUE_SIZE, 5, + EGL_ALPHA_SIZE, 1, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLE_BUFFERS, 0, + EGL_NONE + }; + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + EGLConfig config; + if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE) + { + std::cout << "EGLConfig for a GL_RGB5_A1 surface is not supported, skipping test" << std::endl; + return; + } + + initializeSurface(config); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_EGL_SUCCESS(); + + GLuint program = createProgram(); + ASSERT_NE(0u, program); + drawWithProgram(program); + EXPECT_GL_NO_ERROR(); + glDeleteProgram(program); +} + +// Test creating a surface that supports a EGLConfig without alpha support +TEST_F(EGLSurfaceTest, CreateWithEGLConfig8880Support) +{ + if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d")) + { + std::cout << "D3D Platform not supported in ANGLE" << std::endl; + return; + } + + const EGLint configAttributes[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLE_BUFFERS, 0, + EGL_NONE + }; + + initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + EGLConfig config; + if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE) + { + std::cout << "EGLConfig for a GL_RGB8_OES surface is not supported, skipping test" + << std::endl; + return; + } + + initializeSurface(config); + + eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); + ASSERT_EGL_SUCCESS(); + + GLuint program = createProgram(); + ASSERT_NE(0u, program); + drawWithProgram(program); + EXPECT_GL_NO_ERROR(); + glDeleteProgram(program); +} +} diff --git a/gfx/angle/src/tests/egl_tests/EGLThreadTest.cpp b/gfx/angle/src/tests/egl_tests/EGLThreadTest.cpp new file mode 100755 index 000000000..305ccc25f --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLThreadTest.cpp @@ -0,0 +1,83 @@ +#include "gtest/gtest.h" + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +typedef EGLAPI EGLDisplay EGLAPIENTRY EGLGetDisplay(EGLNativeDisplayType display_id); +typedef EGLAPI EGLBoolean EGLAPIENTRY EGLInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +typedef EGLAPI EGLContext EGLAPIENTRY EGLGetCurrentContext(void); +typedef EGLAPI EGLSurface EGLAPIENTRY EGLGetCurrentSurface(EGLint readdraw); +typedef EGLAPI EGLBoolean EGLAPIENTRY EGLTerminate(EGLDisplay dpy); + +class EGLThreadTest : public testing::Test +{ + public: + virtual void SetUp() {} + virtual void TearDown() {} + + EGLGetDisplay *mGetDisplay; + EGLInitialize *mInitialize; + EGLGetCurrentContext *mGetCurrentContext; + EGLGetCurrentSurface *mGetCurrentSurface; + + EGLDisplay mDisplay; + + HMODULE mEGL; + HMODULE mGLESv2; + + static DWORD WINAPI ThreadingTestEntryPoint(LPVOID thisPointer); + + private: + void ThreadingTest(); +}; + +DWORD WINAPI EGLThreadTest::ThreadingTestEntryPoint(LPVOID lpParameter) +{ + EGLThreadTest *test = (EGLThreadTest *)lpParameter; + test->ThreadingTest(); + return 0; +} + +void EGLThreadTest::ThreadingTest() +{ + mEGL = LoadLibrary(TEXT("libEGL.dll")); + mGLESv2 = LoadLibrary(TEXT("libGLESv2.dll")); + + EXPECT_TRUE(mEGL != NULL); + EXPECT_TRUE(mGLESv2 != NULL); + + mGetDisplay = (EGLGetDisplay *)GetProcAddress(mEGL, "eglGetDisplay"); + mInitialize = (EGLInitialize *)GetProcAddress(mEGL, "eglInitialize"); + mGetCurrentContext = (EGLGetCurrentContext *)GetProcAddress(mEGL, "eglGetCurrentContext"); + mGetCurrentSurface = (EGLGetCurrentSurface *)GetProcAddress(mEGL, "eglGetCurrentSurface"); + + EXPECT_TRUE(mGetDisplay != NULL); + EXPECT_TRUE(mInitialize != NULL); + EXPECT_TRUE(mGetCurrentContext != NULL); + EXPECT_TRUE(mGetCurrentSurface != NULL); + + mDisplay = mGetDisplay(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE); + + EXPECT_TRUE(mDisplay!= EGL_NO_DISPLAY); + + mInitialize(mDisplay, NULL, NULL); + mGetCurrentContext(); +} + +TEST_F(EGLThreadTest, thread_init_crash) +{ + DWORD threadId; + HANDLE threadHandle = CreateThread(NULL, 0, EGLThreadTest::ThreadingTestEntryPoint, this, 0, &threadId); + EXPECT_TRUE(threadHandle != NULL); + + // wait for signal from thread + DWORD waitResult = WaitForSingleObject(threadHandle, 1000); + EXPECT_EQ(waitResult, WAIT_OBJECT_0); + + // crash, because the TLS value is NULL on main thread + mGetCurrentSurface(EGL_DRAW); + mGetCurrentContext(); + + auto terminate = (EGLTerminate *)GetProcAddress(mEGL, "eglTerminate"); + terminate(mDisplay); +} diff --git a/gfx/angle/src/tests/egl_tests/EGLX11VisualTest.cpp b/gfx/angle/src/tests/egl_tests/EGLX11VisualTest.cpp new file mode 100755 index 000000000..4d5179964 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLX11VisualTest.cpp @@ -0,0 +1,216 @@ +// +// Copyright (c) 2015 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. +// + +// EGLX11VisualTest.cpp: tests for EGL_ANGLE_x11_visual extension + +#include <gtest/gtest.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <X11/Xlib.h> + +#include "OSWindow.h" +#include "test_utils/ANGLETest.h" +#include "x11/X11Window.h" + +using namespace angle; + +namespace +{ + +const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; +} + +class EGLX11VisualHintTest : public ::testing::TestWithParam<angle::PlatformParameters> +{ + public: + void SetUp() override + { + mEglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + + mDisplay = XOpenDisplay(NULL); + } + + std::vector<EGLint> getDisplayAttributes(int visualId) const + { + std::vector<EGLint> attribs; + + attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); + attribs.push_back(GetParam().getRenderer()); + attribs.push_back(EGL_X11_VISUAL_ID_ANGLE); + attribs.push_back(visualId); + attribs.push_back(EGL_NONE); + + return attribs; + } + + unsigned int chooseDifferentVisual(unsigned int visualId) + { + int numVisuals; + XVisualInfo visualTemplate; + visualTemplate.screen = DefaultScreen(mDisplay); + + XVisualInfo *visuals = + XGetVisualInfo(mDisplay, VisualScreenMask, &visualTemplate, &numVisuals); + EXPECT_TRUE(numVisuals >= 2); + + for (int i = 0; i < numVisuals; ++i) + { + if (visuals[i].visualid != visualId) + { + int result = visuals[i].visualid; + XFree(visuals); + return result; + } + } + + UNREACHABLE(); + return -1; + } + + protected: + PFNEGLGETPLATFORMDISPLAYEXTPROC mEglGetPlatformDisplayEXT; + Display *mDisplay; +}; + +// Test that display creation fails if the visual ID passed in invalid. +TEST_P(EGLX11VisualHintTest, InvalidVisualID) +{ + // The test platform will log an error in this negative test. + IgnoreANGLEPlatformMessages(); + + static const int gInvalidVisualId = -1; + auto attributes = getDisplayAttributes(gInvalidVisualId); + + EGLDisplay display = + mEglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, attributes.data()); + ASSERT_TRUE(display != EGL_NO_DISPLAY); + + ASSERT_TRUE(EGL_FALSE == eglInitialize(display, nullptr, nullptr)); + ASSERT_EGL_ERROR(EGL_NOT_INITIALIZED); +} + +// Test that context creation with a visual ID succeeds, that the context exposes +// only one config, and that a clear on a surface with this config works. +TEST_P(EGLX11VisualHintTest, ValidVisualIDAndClear) +{ + // We'll test the extension with one visual ID but we don't care which one. This means we + // can use OSWindow to create a window and just grab its visual. + OSWindow *osWindow = CreateOSWindow(); + osWindow->initialize("EGLX11VisualHintTest", 500, 500); + osWindow->setVisible(true); + + Window xWindow = osWindow->getNativeWindow(); + + XWindowAttributes windowAttributes; + ASSERT_NE(0, XGetWindowAttributes(mDisplay, xWindow, &windowAttributes)); + int visualId = windowAttributes.visual->visualid; + + auto attributes = getDisplayAttributes(visualId); + EGLDisplay display = + mEglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, attributes.data()); + ASSERT_NE(EGL_NO_DISPLAY, display); + + ASSERT_TRUE(EGL_TRUE == eglInitialize(display, nullptr, nullptr)); + + // While this is not required by the extension, test that our implementation returns only one + // config, with the same native visual Id that we provided. + int nConfigs = 0; + ASSERT_TRUE(EGL_TRUE == eglGetConfigs(display, nullptr, 0, &nConfigs)); + ASSERT_EQ(1, nConfigs); + + int nReturnedConfigs = 0; + EGLConfig config; + ASSERT_TRUE(EGL_TRUE == eglGetConfigs(display, &config, 1, &nReturnedConfigs)); + ASSERT_EQ(nConfigs, nReturnedConfigs); + + EGLint eglNativeId; + ASSERT_TRUE(EGL_TRUE == eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &eglNativeId)); + ASSERT_EQ(visualId, eglNativeId); + + // Finally, try to do a clear on the window. + EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + ASSERT_NE(EGL_NO_CONTEXT, context); + + EGLSurface window = eglCreateWindowSurface(display, config, xWindow, nullptr); + ASSERT_EGL_SUCCESS(); + + eglMakeCurrent(display, window, window, context); + ASSERT_EGL_SUCCESS(); + + glViewport(0, 0, 500, 500); + glClearColor(0.0f, 0.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + ASSERT_GL_NO_ERROR(); + EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255); + + // Teardown + eglDestroySurface(display, window); + ASSERT_EGL_SUCCESS(); + + eglDestroyContext(display, context); + ASSERT_EGL_SUCCESS(); + + SafeDelete(osWindow); + + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(display); +} + +// Test that EGL_BAD_MATCH is generated when trying to create an EGL window from +// an X11 window whose visual ID doesn't match the visual ID passed at display creation. +TEST_P(EGLX11VisualHintTest, InvalidWindowVisualID) +{ + // Get the default visual ID, as a good guess of a visual id for which display + // creation will succeed. + int visualId; + { + OSWindow *osWindow = CreateOSWindow(); + osWindow->initialize("EGLX11VisualHintTest", 500, 500); + osWindow->setVisible(true); + + Window xWindow = osWindow->getNativeWindow(); + + XWindowAttributes windowAttributes; + ASSERT_NE(0, XGetWindowAttributes(mDisplay, xWindow, &windowAttributes)); + visualId = windowAttributes.visual->visualid; + + SafeDelete(osWindow); + } + + auto attributes = getDisplayAttributes(visualId); + EGLDisplay display = + mEglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, attributes.data()); + ASSERT_NE(EGL_NO_DISPLAY, display); + + ASSERT_TRUE(EGL_TRUE == eglInitialize(display, nullptr, nullptr)); + + + // Initialize the window with a visual id different from the display's visual id + int otherVisualId = chooseDifferentVisual(visualId); + ASSERT_NE(visualId, otherVisualId); + + OSWindow *osWindow = new X11Window(otherVisualId); + osWindow->initialize("EGLX11VisualHintTest", 500, 500); + osWindow->setVisible(true); + + Window xWindow = osWindow->getNativeWindow(); + + // Creating the EGL window should fail with EGL_BAD_MATCH + int nReturnedConfigs = 0; + EGLConfig config; + ASSERT_TRUE(EGL_TRUE == eglGetConfigs(display, &config, 1, &nReturnedConfigs)); + ASSERT_EQ(1, nReturnedConfigs); + + EGLSurface window = eglCreateWindowSurface(display, config, xWindow, nullptr); + ASSERT_EQ(EGL_NO_SURFACE, window); + ASSERT_EGL_ERROR(EGL_BAD_MATCH); + + SafeDelete(osWindow); +} + +ANGLE_INSTANTIATE_TEST(EGLX11VisualHintTest, ES2_OPENGL()); diff --git a/gfx/angle/src/tests/egl_tests/media/yuvtest.inl b/gfx/angle/src/tests/egl_tests/media/yuvtest.inl new file mode 100755 index 000000000..7271cf80a --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/media/yuvtest.inl @@ -0,0 +1,1548 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by scripts/bmp_to_yuv.py using data from yuvtest.bmp +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +static const size_t yuvtest_width = 128; +static const size_t yuvtest_height = 128; +static const unsigned char yuvtest_data[] = +{ + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,132,16,16,16,16,105,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,23,16,16,16,16,16,16,44,153,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,16,16,16,16,16,16,16,16,16,78,228,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,16,16,16,173,44,16,16,16,16,16,16,44,153,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,16,16,16,228,235,235,221,112,16,16,16,16,16,78,228, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,37,16,16,92,235,235,235,235,153,44,16,16,16,16,16, + 92,228,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,212,186,186,186,186,186,186,186,186,186,203,234,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,146,16,16,16,235,235,235,235,235,235,221,112,16,16,16, + 16,16,16,92,228,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,219,187,160,150,150,150,140,127,121,121,121, + 152,186,186,186,186,186,186,186,186,186,186,186,186,186,203,234, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,16,16,16,105,235,235,235,235,235,235,235,153,44,16, + 16,16,16,16,78,228,235,235,235,235,235,235,235,235,235,219, + 187,160,150,150,150,150,150,149,132,121,121,121,121,121,121,152, + 186,186,186,186,186,186,186,185,154,134,134,134,134,134,134,134, + 134,134,134,169,232,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,213,171,135,120,120,120,120,120,120,120, + 120,120,120,120,120,167,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,232, + 172,134,27,16,16,16,130,134,134,134,134,134,134,134,169,151, + 44,16,16,16,16,44,153,235,235,235,235,235,219,187,160,150, + 150,150,150,150,150,150,149,129,121,121,121,121,121,121,121,185, + 186,186,185,146,121,121,122,131,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134,169,232,235,235,235,235,235,235, + 235,235,235,235,231,156,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,120,124,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,187,134, + 134,134,101,24,16,16,57,134,134,134,134,134,134,134,134,134, + 134,134,75,16,16,16,16,78,228,219,187,160,150,150,150,150, + 150,150,150,150,150,148,134,121,121,121,121,136,172,225,212,186, + 186,186,163,150,150,149,138,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134,134,134,134,169,232,235,235,235, + 235,235,213,171,135,120,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,135,192,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,137,134, + 134,134,134,86,16,16,16,134,134,134,134,134,134,134,134,134, + 134,134,134,86,24,16,16,16,45,129,150,150,150,150,150,158, + 184,214,235,235,172,121,121,121,121,178,235,235,235,235,188,186, + 186,188,200,158,149,139,134,134,134,143,158,136,121,121,121,121, + 146,178,166,140,134,134,134,134,134,134,134,134,147,197,199,142, + 120,120,120,120,120,120,120,164,206,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,134,134, + 134,194,235,235,37,16,16,166,235,235,235,235,235,197,147,134, + 134,134,134,134,126,68,16,16,16,20,87,150,158,184,214,235, + 235,235,235,199,125,121,121,125,181,235,235,235,235,226,186,186, + 186,217,235,232,155,134,134,134,141,150,150,174,225,178,136,121, + 121,121,154,186,186,186,200,196,147,134,134,134,130,123,120,120, + 120,120,120,120,120,131,185,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,134,134, + 134,235,235,235,112,16,16,57,235,235,235,235,235,235,235,235, + 235,235,206,147,134,134,82,20,16,16,16,72,228,235,235,235, + 235,232,157,121,121,121,125,225,235,235,235,235,235,203,186,186, + 202,235,232,163,134,134,134,161,155,150,150,150,174,232,235,235, + 228,172,121,151,186,186,186,165,113,111,120,122,120,120,120,120, + 120,120,135,167,206,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,134,134, + 134,235,235,235,215,16,16,16,235,235,235,235,235,235,235,235, + 235,235,235,235,145,136,134,115,42,16,16,16,78,228,235,235, + 235,172,121,121,121,125,181,235,235,235,235,235,235,188,186,186, + 226,232,163,134,134,134,184,235,230,187,150,150,150,160,203,235, + 231,158,111,111,149,186,186,186,151,119,120,120,120,120,121,126, + 133,142,231,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,233,169,189, + 189,189,189,189,189,16,16,16,87,189,189,189,195,217,235,235, + 235,235,235,235,150,150,150,167,134,71,16,16,16,71,228,235, + 235,125,121,121,168,225,235,235,235,235,235,235,235,186,186,186, + 232,163,134,134,134,184,235,235,235,235,192,150,150,150,148,130, + 111,111,111,111,111,149,166,133,120,120,120,120,120,121,133,134, + 134,134,134,152,232,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,233,202,189,189, + 189,189,189,189,189,32,16,16,16,87,189,189,189,189,195,217, + 235,235,235,235,150,150,150,235,184,134,75,16,16,16,20,77, + 121,98,121,121,235,235,235,235,235,235,235,235,212,186,186,185, + 163,134,134,134,184,235,235,235,235,235,235,200,153,126,111,111, + 111,111,111,125,148,134,120,120,120,120,121,152,224,200,129,132, + 134,134,134,134,137,232,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,233,202,189,189,189, + 189,189,189,189,189,140,27,16,16,16,189,189,189,189,189,189, + 195,217,235,235,150,150,150,235,235,194,147,75,16,16,16,16, + 16,16,52,157,235,235,235,235,235,235,235,235,188,186,185,149, + 134,134,134,184,235,235,235,235,235,235,235,235,163,111,111,111, + 112,118,127,120,120,120,120,120,122,150,139,121,153,235,235,206, + 140,134,134,134,134,134,175,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,233,202,189,189,189,161, + 134,134,134,235,235,235,173,16,16,16,235,232,212,192,189,189, + 189,189,189,189,189,189,176,233,235,235,235,216,109,31,16,16, + 16,16,16,152,235,235,235,235,235,235,235,235,186,185,149,134, + 134,134,184,235,235,235,235,235,235,235,231,158,111,111,115,120, + 120,120,120,120,120,120,131,159,180,186,174,121,121,199,235,235, + 235,227,144,134,134,134,134,146,231,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,220,198,189,189,189,212,197, + 134,134,134,163,235,235,235,37,16,16,166,235,235,232,212,192, + 189,189,189,189,189,189,189,189,189,189,205,233,235,184,119,89, + 49,16,16,37,153,235,235,235,235,235,235,234,170,144,134,134, + 134,184,235,235,235,235,235,235,235,231,146,112,116,120,120,120, + 120,120,120,128,167,206,235,231,186,186,186,123,121,143,235,235, + 235,235,223,122,132,134,134,134,137,228,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,210,189,189,189,189,212,235,235, + 144,134,134,134,203,235,235,112,16,16,57,235,235,235,235,232, + 212,195,189,189,189,189,189,189,189,189,189,189,194,208,165,133, + 123,20,16,16,16,59,225,235,235,235,232,157,134,134,134,134, + 184,235,235,235,235,235,235,235,235,153,117,120,120,120,120,120, + 123,132,142,150,174,235,235,235,191,186,186,165,121,121,199,235, + 235,235,235,196,129,132,134,134,134,139,232,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,213,189,189,189,191,213,235,235,235, + 206,147,134,134,134,175,235,215,23,16,16,166,235,235,235,235, + 235,235,235,179,150,164,187,189,189,189,189,189,189,189,189,183, + 165,111,24,16,16,16,57,225,235,235,166,135,169,189,189,189, + 189,189,189,189,189,189,185,171,127,120,120,120,120,120,135,188, + 208,155,150,150,150,208,235,235,215,186,186,186,121,121,143,232, + 235,235,235,235,235,229,151,134,134,134,163,232,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,191,189,189,191,231,235,235,235,235, + 235,225,137,134,134,134,235,235,112,16,16,57,228,235,235,235, + 235,235,235,152,150,150,219,235,235,217,195,189,189,189,189,189, + 189,189,178,92,16,16,16,16,57,140,135,173,189,189,189,189, + 189,189,189,189,180,148,125,120,120,120,120,120,149,199,235,235, + 235,230,179,150,150,166,235,235,235,186,186,186,125,121,121,161, + 235,235,235,235,235,235,235,122,134,134,134,169,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,189,189,189,217,235,235,235,235,235, + 235,235,203,134,134,134,170,217,215,23,16,16,92,235,235,235, + 235,235,235,150,150,150,235,235,235,235,235,235,227,177,180,189, + 189,189,189,189,102,16,16,16,16,57,169,189,189,189,189,189, + 189,189,170,140,120,120,120,120,120,122,146,178,233,235,235,235, + 235,235,227,152,150,150,195,235,235,186,186,186,189,121,121,121, + 235,235,235,235,235,235,235,111,122,134,134,134,160,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,189,189,189,235,235,235,235,235,235, + 235,235,235,144,134,134,134,149,185,127,16,16,16,105,235,235, + 235,235,235,150,150,150,235,235,235,235,235,235,235,125,121,135, + 200,191,189,189,189,124,38,16,16,16,124,178,172,143,156,149, + 139,120,120,120,120,120,120,128,156,185,189,189,195,176,95,95, + 152,235,235,195,150,150,152,222,235,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,111,111,132,134,134,134,213,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,233,189,189,189,235,235,235,235,235,235, + 235,235,235,203,139,134,134,134,152,186,33,16,16,16,235,235, + 235,235,235,150,150,150,235,235,235,235,235,235,228,121,121,121, + 208,189,189,189,189,189,189,32,23,58,107,120,120,120,120,120, + 120,120,120,120,120,149,150,111,111,152,189,189,189,189,163,97, + 95,95,95,152,168,150,150,168,235,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,111,111,117,147,134,134,182,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,210,189,189,191,235,235,235,235,235,235, + 235,235,235,235,229,177,134,134,134,149,138,16,16,16,78,235, + 235,235,235,150,150,150,235,235,235,235,235,235,192,121,121,158, + 189,189,189,189,189,189,180,126,115,120,120,120,120,120,120,120, + 120,120,123,134,203,235,115,111,111,176,216,192,189,189,189,163, + 97,95,95,95,224,152,150,150,208,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,111,111,111,210,134,134,140,197,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,191,189,189,213,235,235,235,235,235,235, + 235,235,235,235,235,235,144,134,134,134,170,32,16,16,16,144, + 234,235,235,150,150,150,235,235,235,235,235,235,153,121,127,189, + 189,189,201,213,162,128,120,120,120,120,120,117,101,140,156,172, + 173,166,148,134,137,187,111,111,111,235,235,232,210,189,189,189, + 163,97,95,95,235,187,150,150,166,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,111,111,111,235,144,134,134,134,163, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,233,189,189,189,235,235,235,235,235,235,235, + 235,235,235,235,235,235,206,147,134,134,146,138,37,16,16,48, + 194,234,235,150,150,150,235,235,235,235,235,235,125,146,185,189, + 185,165,139,121,120,120,120,120,120,127,68,23,16,21,108,189, + 189,189,189,189,189,189,182,154,132,175,210,235,235,212,189,189, + 189,157,95,95,235,227,152,150,150,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,111,111,111,235,210,140,134,134,134, + 203,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,210,189,189,191,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,225,137,134,134,157,174,21,16,16, + 64,187,217,150,150,150,235,235,235,235,235,233,168,174,156,136, + 120,120,120,120,120,120,120,138,165,212,160,21,16,16,16,65, + 184,189,189,189,189,189,189,189,188,173,160,146,134,147,193,189, + 189,189,95,95,235,235,192,150,150,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,123,111,115,235,235,229,169,134,134, + 153,232,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,191,189,189,213,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,194,134,134,134,147,123,16,16, + 16,64,186,182,163,150,235,235,235,235,235,178,134,120,120,120, + 120,120,120,120,124,154,178,189,189,235,235,163,53,16,16,16, + 70,184,189,189,189,189,189,189,189,189,189,189,182,154,134,184, + 189,189,142,96,235,235,232,166,150,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,200,142,188,235,235,235,225,137,134, + 134,163,232,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,189,189,189,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,184,134,134,134,134,89,16, + 16,16,133,186,186,178,227,235,235,199,139,120,120,120,120,120, + 120,123,127,170,235,227,189,189,189,235,235,215,186,96,16,16, + 16,69,189,189,191,128,150,179,189,189,189,189,189,189,182,181, + 189,189,179,123,232,235,235,219,150,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,194,134, + 134,134,169,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,189,189,189,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,194,140,134,134,134,90, + 16,16,49,181,186,186,188,183,142,120,120,120,120,122,124,128, + 133,134,184,235,233,201,189,189,204,235,235,235,191,186,101,16, + 16,16,139,189,189,172,113,111,229,217,207,192,189,189,189,189, + 189,189,189,151,134,169,232,235,150,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,184, + 134,134,134,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,189,189,189,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,229,144,134,134,123, + 20,16,16,59,168,150,129,120,120,120,120,122,148,133,134,134, + 134,184,235,235,210,189,189,189,227,235,235,235,215,186,186,86, + 16,16,36,125,189,189,167,113,235,235,235,232,212,192,189,189, + 189,189,189,184,166,148,162,181,150,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 134,134,134,197,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,189,189,189,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,203,140,134,134, + 86,35,75,107,120,120,120,120,120,122,150,183,148,134,134,137, + 187,235,235,235,191,189,189,212,235,235,235,235,235,211,186,170, + 21,16,16,16,65,189,189,167,233,235,235,235,235,232,210,184, + 189,189,189,189,189,189,182,156,148,186,186,186,235,121,121,121, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 144,134,134,134,163,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,227,189,189,189,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,229,179,133, + 124,120,120,120,120,120,120,127,150,183,189,168,134,134,131,225, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,217,192, + 143,28,16,16,16,135,189,189,202,235,235,235,235,152,95,105, + 137,176,189,189,189,189,189,189,189,189,189,184,165,121,121,121, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 203,140,134,134,134,232,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,205,189,189,204,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,192,122, + 120,120,120,120,111,93,182,189,189,189,169,134,134,134,176,189, + 227,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,209,84,16,16,41,189,189,189,167,150,150,150,150,150,150, + 150,153,189,189,189,186,189,189,189,189,189,189,173,131,122,125, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,229,144,134,134,169,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,191,189,189,227,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,213,171,135,120,120, + 120,120,106,42,16,16,76,189,189,175,134,134,134,160,186,186, + 186,212,235,235,189,189,189,187,160,150,150,150,150,150,150,150, + 150,150,137,20,16,16,88,189,189,186,153,150,150,150,150,150, + 150,150,189,189,189,126,157,185,189,189,189,189,189,182,155,191, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,194,134,134,134,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,231,156,120,120,120,120,120, + 139,202,137,75,16,16,16,184,189,134,134,134,163,186,186,186, + 186,186,194,217,189,189,189,150,150,150,150,150,150,150,150,150, + 150,150,150,95,16,16,19,151,189,189,175,149,132,121,121,121, + 121,121,189,189,189,162,186,186,186,182,164,189,189,189,189,185, + 225,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,232,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,231,153,120,120,120,120,131,174, + 231,235,203,147,27,16,16,65,184,134,134,184,235,199,137,172, + 186,186,186,186,189,189,189,150,150,150,150,150,150,150,150,150, + 150,160,174,192,58,16,16,42,189,189,189,132,121,121,121,121, + 121,121,189,189,189,186,186,186,186,152,136,179,188,189,189,189, + 188,176,232,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,144,134,134,169,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,231,164,120,120,120,120,164,206,235,235, + 235,235,235,235,125,16,16,16,65,134,160,235,235,235,199,129, + 152,182,186,186,189,189,189,182,214,235,235,235,235,235,235,235, + 235,235,235,235,198,19,16,16,99,189,189,179,134,134,134,134, + 134,134,189,189,189,134,134,134,134,134,134,134,137,161,188,189, + 189,189,173,197,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,194,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,235,235,235,231,164,120,120,120,120,120,177,235,235,235,235, + 235,235,235,235,175,76,16,16,16,97,134,147,197,235,235,225, + 149,127,158,186,189,189,189,188,212,225,235,235,235,235,235,232, + 172,134,134,134,134,75,16,16,20,161,189,189,146,134,134,134, + 134,134,189,189,189,134,134,134,134,134,134,134,134,134,146,182, + 189,189,189,184,178,222,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,235,235,199,142,120,120,120,120,135,188,235,235,235,235,235, + 235,235,235,216,134,154,87,16,16,38,130,134,134,163,229,174, + 150,146,128,154,189,189,189,186,186,186,205,235,235,232,172,134, + 134,134,134,134,134,130,38,16,16,49,184,189,163,134,134,134, + 134,134,189,189,189,134,134,134,134,134,134,134,134,134,134,137, + 172,189,189,189,189,189,190,208,224,235,235,235,235,235,235,235, + 235,235,235,235,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 235,231,156,120,120,120,120,135,188,235,235,235,235,235,235,235, + 235,235,175,134,134,173,173,21,16,16,49,134,134,134,136,143, + 150,150,184,177,189,189,189,186,186,186,186,170,229,163,134,134, + 134,134,134,134,134,131,100,19,16,16,65,189,190,186,186,186, + 186,175,189,189,189,235,235,235,235,235,235,235,229,184,147,134, + 134,156,182,189,189,189,189,189,189,202,233,235,235,235,235,235, + 235,235,235,235,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,235,235,235, + 231,153,120,120,120,120,115,111,111,111,111,111,111,111,154,231, + 235,216,134,134,134,188,189,118,16,16,16,102,134,134,134,134, + 136,170,235,235,189,189,189,146,180,186,185,154,134,134,134,134, + 147,194,199,142,111,111,111,83,16,16,16,135,189,188,186,192, + 173,95,189,189,189,231,235,235,235,235,235,235,235,235,235,235, + 229,179,134,144,165,182,189,189,189,189,173,169,232,235,235,235, + 235,235,235,235,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,189,189,189,233,235,235,235,235,235,235,235,231, + 153,120,120,120,117,112,111,111,111,111,111,111,111,111,111,111, + 111,140,134,134,147,189,189,189,71,16,16,41,139,134,134,134, + 134,134,134,169,189,189,189,192,152,182,157,134,134,134,134,149, + 121,121,121,114,111,111,113,234,92,16,16,49,184,189,207,235, + 235,165,189,189,189,134,235,235,235,235,235,235,235,235,235,235, + 235,235,197,147,134,134,144,169,189,189,189,189,189,170,135,147, + 197,235,235,235,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,194,189,189,202,233,235,235,235,235,235,199,142, + 120,120,120,115,111,111,111,111,111,111,111,111,111,111,111,111, + 115,134,134,134,115,189,189,189,102,19,16,16,16,51,147,138, + 134,134,134,134,189,189,189,235,235,186,134,134,134,140,165,168, + 121,121,114,111,111,111,176,208,170,21,16,16,65,184,199,235, + 235,235,189,189,189,95,169,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,197,147,161,189,189,189,189,189,184,166, + 148,163,235,235,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,216,189,189,189,202,233,235,235,231,156,120,120, + 120,120,117,111,111,176,235,235,235,235,235,235,235,188,127,124, + 134,134,134,127,111,189,189,189,111,72,16,16,16,16,92,185, + 184,147,134,134,189,189,189,156,179,134,134,134,135,186,186,186, + 146,115,111,111,111,173,212,186,186,117,16,16,16,65,184,227, + 235,235,189,189,189,95,99,213,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,229,182,182,189,189,189,189,189, + 189,182,154,134,134,134,134,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,212,189,189,189,202,233,231,153,120,120,120, + 124,156,111,111,142,235,235,235,235,235,235,235,235,235,216,134, + 134,134,134,115,111,189,189,189,111,111,75,28,16,16,34,108, + 111,111,122,134,189,189,189,134,134,134,134,133,129,180,186,186, + 186,165,111,111,173,212,186,186,186,188,125,16,16,16,65,208, + 235,235,189,189,189,95,95,130,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,197,147,156,182,189,189, + 189,189,189,173,134,134,137,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,212,189,189,189,202,170,120,120,120,167, + 224,146,111,111,184,235,235,235,235,235,235,235,235,235,166,134, + 134,147,187,235,235,189,189,189,150,150,150,148,21,16,16,43, + 108,111,111,120,189,189,189,134,134,134,134,122,116,140,183,186, + 186,186,140,137,234,188,186,186,188,217,235,125,16,16,16,69, + 235,235,189,189,189,95,95,95,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,197,155,165, + 186,189,189,189,134,134,137,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,212,189,189,187,123,120,120,177,235, + 235,115,111,111,223,235,235,235,235,235,235,235,235,216,134,134, + 134,216,235,235,227,189,189,189,192,150,150,150,102,16,16,16, + 43,108,111,111,182,189,189,151,134,134,134,128,112,111,126,180, + 186,186,186,168,175,186,186,188,217,235,235,235,121,16,16,16, + 132,232,189,189,189,95,95,95,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 232,194,189,188,134,147,197,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,209,146,120,120,120,124,235,235, + 235,111,111,111,235,235,235,235,235,235,235,235,187,134,134,134, + 166,235,235,235,205,189,189,204,235,192,150,150,150,82,16,16, + 16,78,228,235,192,189,189,179,135,134,134,134,131,120,111,135, + 182,186,186,186,186,186,186,212,235,235,235,235,235,100,16,16, + 22,186,189,189,201,95,95,95,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,199,142,120, + 156,222,201,217,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,171,120,120,120,120,163,233,235, + 235,111,111,111,235,235,235,235,235,235,235,235,137,134,134,134, + 216,235,235,235,191,189,189,227,235,235,200,155,150,150,82,16, + 16,16,92,232,146,188,189,189,173,172,134,134,134,134,131,120, + 116,170,186,186,186,186,149,137,232,235,235,235,235,206,49,16, + 16,39,124,189,216,95,95,95,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,181,120,120,120,120,120, + 120,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,231,124,120,120,129,161,189,202,233, + 235,111,111,111,235,235,235,235,235,235,235,232,134,134,134,187, + 235,235,235,235,189,189,189,235,235,235,235,230,192,155,150,82, + 16,16,16,167,133,156,189,189,189,202,191,134,134,134,134,134, + 137,166,186,186,186,186,135,111,118,188,235,235,235,233,163,21, + 16,16,16,65,224,95,95,95,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,181,120,120,120,120,120,120,120,124, + 192,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,171,120,120,124,212,189,189,189,189, + 189,172,123,111,235,235,235,235,235,235,232,163,134,134,137,235, + 235,235,235,235,189,189,189,235,235,235,235,235,235,230,187,150, + 29,16,16,48,130,134,161,189,189,189,166,112,122,132,134,134, + 134,134,149,185,186,186,173,113,111,111,123,162,204,235,227,130, + 27,16,16,16,78,92,95,95,235,235,235,235,235,235,235,235, + 235,235,199,142,120,120,120,120,120,120,120,120,120,135,171,224, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,124,120,120,181,235,212,189,189,189, + 189,189,187,148,235,235,235,235,235,235,179,134,134,134,113,95, + 95,95,95,95,189,189,189,113,182,235,235,235,235,235,235,176, + 95,16,16,16,57,134,137,211,189,189,187,123,111,164,177,137, + 134,134,134,157,187,186,186,165,113,111,111,111,111,111,138,178, + 178,92,16,16,16,38,95,95,235,235,235,235,235,213,171,135, + 120,120,120,120,120,120,120,120,120,120,120,135,192,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,231,120,120,120,235,235,235,217,195,189, + 189,189,189,189,189,189,208,235,235,235,137,134,134,116,95,95, + 95,95,95,95,189,189,189,95,95,113,182,235,235,235,235,230, + 160,75,16,16,16,136,197,214,178,189,189,172,173,208,186,183, + 157,134,134,134,134,134,149,186,167,114,111,111,111,111,111,131, + 189,187,114,120,120,120,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,120,120,120,120,135,192,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,164,120,120,124,235,235,235,235,235,235, + 228,172,189,189,189,189,189,217,235,216,134,134,134,95,95,95, + 95,95,95,95,189,189,189,95,95,95,95,113,182,235,235,235, + 216,129,27,16,16,60,185,119,125,187,189,189,194,186,186,186, + 188,175,134,134,134,134,134,170,186,178,165,166,131,111,111,122, + 120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, + 120,120,135,171,224,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,213,120,120,120,181,235,235,235,235,235,235, + 235,111,148,179,189,189,189,189,189,189,189,184,179,119,95,95, + 235,235,235,235,189,189,189,165,103,95,95,95,95,126,231,235, + 216,134,86,16,16,16,43,111,111,149,189,189,189,188,186,188, + 231,235,197,147,134,134,134,139,166,186,166,135,120,120,120,120, + 120,120,120,120,120,120,120,120,120,120,120,120,120,135,167,206, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,160,120,120,156,235,235,235,235,235,235,235, + 235,111,111,111,220,192,189,189,189,189,189,189,189,189,178,130, + 235,235,235,235,189,189,189,235,226,165,103,95,95,95,148,187, + 134,134,134,74,16,16,16,81,120,199,212,189,189,189,190,216, + 235,235,235,235,225,137,134,134,130,126,120,120,120,120,120,120, + 120,120,129,147,93,19,16,16,16,43,119,162,204,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,124,120,120,213,235,235,235,235,235,235,235, + 235,111,111,111,235,232,212,194,189,189,189,189,189,189,189,189, + 189,189,195,217,189,189,189,235,235,235,226,157,95,95,118,134, + 134,134,134,117,55,16,16,16,70,150,190,188,189,189,189,195, + 217,235,235,235,235,206,134,123,120,120,120,120,120,120,120,129, + 161,189,189,183,103,77,22,16,16,16,37,96,111,146,231,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,120,120,120,235,235,235,235,235,235,235,235, + 235,111,111,111,235,235,235,197,134,134,160,227,210,187,189,189, + 189,189,189,189,189,189,189,217,235,235,235,235,139,102,134,134, + 134,133,122,111,102,19,16,16,16,150,151,186,188,189,189,189, + 189,195,187,142,120,120,120,120,120,120,121,129,152,186,189,189, + 189,189,189,189,95,165,206,93,16,16,16,19,66,111,123,162, + 204,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,231,120,120,120,235,235,235,235,235,235,235,235, + 235,111,111,111,235,235,232,156,134,134,194,235,235,220,144,178, + 189,189,189,189,189,189,189,189,194,208,224,235,223,129,134,134, + 132,120,111,111,113,138,16,16,16,145,171,186,186,185,147,120, + 120,120,120,120,120,120,120,120,122,126,133,134,151,188,189,189, + 189,189,189,189,139,235,235,235,139,23,16,16,16,58,111,111, + 111,146,231,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,171,120,120,124,235,235,235,235,235,235,235,235, + 235,111,111,111,231,235,179,134,134,134,225,235,235,235,157,95, + 95,126,210,195,189,189,189,189,189,189,189,189,189,189,189,189, + 189,189,189,189,189,189,32,16,16,91,120,120,120,120,120,120, + 120,120,120,120,120,120,129,150,183,189,189,189,189,189,189,187, + 133,189,189,189,208,235,235,235,235,201,64,16,16,16,55,111, + 111,111,146,231,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,124,120,120,181,235,235,235,235,235,235,235,235, + 235,123,111,111,154,235,137,134,134,187,235,235,235,235,222,99, + 95,95,134,231,235,189,189,189,189,189,189,189,189,189,189,189, + 189,189,189,189,189,189,118,81,120,120,120,120,120,120,120,120, + 120,120,129,150,183,189,189,189,189,189,189,189,189,189,188,162, + 106,189,189,189,235,235,235,235,235,235,235,37,16,16,16,16, + 49,108,111,123,162,204,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,184,111,111,111,229,134,134,134,235,235,235,235,235,235,178, + 95,95,95,134,235,194,189,189,189,189,189,189,189,189,189,189, + 189,189,189,176,150,129,120,120,120,120,120,120,120,120,129,161, + 189,189,189,189,189,189,189,189,189,189,189,189,188,165,139,134, + 134,189,189,189,235,235,235,235,235,235,235,173,30,16,16,16, + 16,28,75,111,111,111,111,154,231,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,111,111,111,194,134,134,160,235,235,235,235,235,235,235, + 165,95,95,95,191,222,194,189,189,189,189,188,173,159,135,118, + 102,109,121,120,120,120,120,120,120,120,107,55,166,227,179,150, + 150,150,150,167,203,189,189,189,189,189,189,184,164,170,137,134, + 134,189,189,189,235,235,235,235,235,235,235,235,173,44,16,16, + 16,16,16,16,16,49,108,111,146,231,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,123,111,112,136,134,134,194,235,235,235,235,235,235,235, + 235,152,95,95,95,96,132,139,188,189,189,189,178,161,142,125, + 120,120,120,120,120,120,120,128,159,86,16,16,57,235,235,214, + 163,150,150,150,174,216,195,189,189,189,189,189,189,189,188,165, + 134,189,189,189,134,158,210,235,235,235,235,235,235,235,235,146, + 30,16,16,16,16,16,28,75,111,127,188,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,184,111,124,134,134,134,225,235,235,235,235,235,235,235, + 235,222,99,113,134,134,134,134,151,170,150,129,120,120,120,120, + 120,120,120,128,167,200,179,186,186,169,21,16,16,132,235,235, + 235,192,150,150,150,175,173,146,135,154,178,189,189,189,189,189, + 184,189,189,189,134,134,134,138,216,235,235,235,235,235,235,235, + 221,125,44,16,16,16,16,16,16,16,55,123,162,204,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,235,173,133,134,134,144,231,235,235,235,235,235,235,235, + 235,235,164,131,126,122,120,120,120,120,120,120,120,120,120,120, + 127,146,162,208,223,200,186,186,186,152,68,16,16,23,201,235, + 235,235,187,150,150,150,119,95,95,95,95,131,196,192,189,189, + 189,189,189,187,134,134,134,134,133,150,232,235,235,235,235,235, + 235,235,235,235,146,30,16,16,16,16,16,16,49,108,127,188, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,235,216,134,134,134,111,154,235,235,235,235,235,235,235, + 235,197,124,120,120,120,120,120,120,120,120,120,118,112,114,164, + 189,189,189,189,189,189,188,187,158,121,118,36,16,16,44,153, + 235,191,121,132,150,150,150,110,95,108,161,231,235,232,210,189, + 189,189,189,194,170,135,133,134,134,134,144,232,235,235,235,235, + 235,235,235,235,235,221,125,44,16,16,16,16,16,43,108,111, + 146,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,235,169,134,134,127,111,111,111,111,111,111,111,112,116, + 119,120,120,120,120,120,120,120,120,117,110,101,95,95,95,95, + 139,178,189,189,189,189,189,189,189,170,160,124,20,16,16,16, + 38,95,95,96,139,150,150,150,201,235,235,235,235,235,235,217, + 192,189,187,186,200,235,179,134,134,134,134,146,197,235,235,235, + 235,235,235,235,235,235,235,235,173,44,16,16,16,16,16,49, + 108,111,162,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,235,137,134,134,125,111,111,112,116,119,120,120,120,120, + 120,120,120,121,121,114,111,173,235,231,200,169,143,121,95,95, + 95,95,113,148,189,189,189,189,189,189,189,189,129,27,16,16, + 16,142,121,116,156,158,150,150,160,224,235,235,235,235,235,235, + 235,211,186,186,186,220,235,229,152,134,134,134,134,163,232,235, + 235,235,235,235,235,235,235,235,235,235,235,125,16,16,16,16, + 28,75,115,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,200,125,119,120,120,120,120,120,120,120, + 120,121,126,132,111,127,184,235,235,235,235,235,235,235,235,208, + 95,95,95,113,186,187,188,171,189,189,189,189,189,178,16,16, + 16,76,184,189,189,194,179,169,162,168,222,235,235,235,235,235, + 235,235,206,186,186,196,235,235,235,190,140,134,134,134,163,232, + 235,235,235,235,235,235,235,235,235,235,235,235,153,44,16,16, + 16,16,65,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,235,235,235,235,235,235,235,235,235, + 235,235,235,134,131,126,135,120,120,120,120,120,120,120,134,137, + 130,134,147,197,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,224,213,204,180,189,32,16, + 16,16,65,189,189,189,189,189,189,189,189,189,189,189,189,195, + 217,235,231,188,186,186,220,235,235,235,229,179,134,134,134,163, + 232,235,235,235,235,235,235,235,235,235,235,235,235,235,146,30, + 16,16,16,92,228,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,120,120,120,167,235,235,235,235,199,142,120,120, + 120,120,120,120,120,120,120,120,120,124,167,206,235,235,179,134, + 134,134,216,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,213,125,98,31, + 16,16,16,141,189,189,189,189,189,189,189,189,189,189,189,189, + 189,189,189,189,188,186,186,203,234,235,235,235,184,134,134,134, + 147,197,235,235,235,235,235,235,235,235,235,235,235,235,235,221, + 37,16,16,16,92,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,131,120,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,120,120,120,131,171,224,235,235,235,235,137,134, + 134,184,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,192,125,121, + 59,16,16,57,228,227,220,212,198,185,189,189,189,189,189,189, + 189,189,189,189,189,186,186,186,200,235,235,235,235,184,134,134, + 134,134,156,219,235,235,235,235,235,235,235,235,235,235,235,235, + 173,44,16,16,16,16,105,235,235,235,235,235,235,235,235,235, + 235,235,235,235,203,128,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,122,126,206,235,235,235,235,235,235,232,134,134, + 134,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,210,136, + 111,19,16,16,78,228,235,235,235,230,176,150,150,150,195,212, + 195,189,189,195,208,192,186,186,186,220,235,235,235,235,194,140, + 134,134,134,137,187,235,235,235,235,235,235,235,235,235,235,235, + 235,235,37,16,16,16,16,105,235,235,235,235,235,235,235,235, + 235,235,235,235,235,203,135,120,120,120,120,120,135,171,224,235, + 235,235,235,134,134,134,235,235,235,235,235,235,235,179,134,134, + 137,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,235,228, + 157,78,16,16,16,78,235,235,235,235,235,190,150,150,152,222, + 235,235,235,235,235,235,206,186,186,196,235,235,235,235,235,229, + 184,137,134,134,134,163,232,235,235,235,235,235,235,235,235,235, + 235,235,173,44,16,16,16,16,78,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,235,235,235,235,235,235,232,137,134,134, + 187,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,235,235, + 235,175,68,16,16,16,166,235,235,235,235,232,166,150,150,168, + 232,235,235,235,235,235,231,188,186,186,220,235,235,235,235,235, + 235,219,156,134,134,134,163,232,235,235,235,235,235,235,235,235, + 235,235,235,235,173,30,16,16,16,166,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,235,235,235,235,235,235,175,134,134,137, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,235,235, + 235,232,143,59,16,16,44,201,235,235,235,235,219,152,150,150, + 174,232,235,235,235,235,235,208,186,186,186,200,235,235,235,235, + 235,235,235,182,134,134,134,163,232,235,235,235,235,235,235,235, + 235,235,235,235,235,173,44,16,16,16,105,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,235,235,235,235,235,229,137,134,134,187, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,235,235, + 235,235,213,114,19,16,16,46,153,235,235,235,235,198,150,150, + 150,174,232,235,235,235,235,231,188,186,186,186,220,235,235,235, + 235,235,235,235,184,134,134,134,163,232,235,235,235,235,235,235, + 235,235,235,235,235,235,215,23,16,16,16,105,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,235,235,235,235,235,197,134,134,160,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,235,235, + 235,235,235,203,87,16,16,16,46,199,235,235,235,235,192,150, + 150,150,174,232,235,235,235,235,220,192,186,186,186,200,235,235, + 235,235,235,235,235,184,134,134,134,163,232,235,235,235,235,235, + 235,235,235,235,235,235,235,166,30,16,16,16,228,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,235,235,235,235,232,156,134,134,194,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,208, + 95,95,95,235,186,186,186,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,115,16,16,16,96,192,235,235,235,235,192, + 150,150,150,174,232,235,235,235,235,231,188,186,186,186,220,235, + 235,235,235,235,235,235,184,134,134,134,163,232,235,235,235,235, + 235,235,235,235,235,235,235,235,173,30,16,16,92,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,134,134,134,232,235,235,235,172,134,134,134,225,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,139, + 95,95,139,235,191,186,186,220,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,101,16,16,36,118,153,232,235,235,235, + 192,150,150,150,174,235,235,235,235,235,220,192,186,186,196,234, + 235,235,235,235,235,235,235,184,134,134,134,163,235,235,235,235, + 235,235,235,235,235,235,235,235,235,146,16,16,23,228,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,144,134,134,163,232,235,216,134,134,134,187,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,208,95, + 95,95,208,235,208,186,186,196,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,215,22,16,16,46,118,153,232,235,235, + 235,192,150,150,150,208,235,235,235,235,235,231,188,186,186,200, + 235,235,235,235,235,235,235,235,184,134,134,134,187,235,235,235, + 235,235,235,235,235,235,235,235,235,235,153,71,153,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,194,134,134,134,169,235,169,134,134,166,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,139,95, + 95,139,235,235,231,186,186,186,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,146,16,16,16,46,118,153,232,235, + 235,235,184,150,150,166,235,235,235,235,235,235,215,186,186,186, + 220,235,235,235,235,235,235,235,235,182,134,134,137,219,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,184,134,134,134,175,137,134,134,216,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,208,95,95, + 95,208,235,235,235,186,186,186,234,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,125,16,16,16,39,118,121,168, + 235,235,227,152,150,150,195,235,235,235,235,235,235,206,186,186, + 186,203,234,235,235,235,235,235,235,232,153,134,134,144,175,210, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,144,134,134,134,134,134,134,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,139,95,95, + 139,235,235,235,235,191,186,186,203,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,125,16,16,16,56,121,125, + 235,235,235,192,150,150,152,222,235,235,235,235,235,231,188,186, + 186,186,203,235,235,235,235,235,235,235,216,137,134,134,134,134, + 166,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,206,140,134,134,134,134,137,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,226,99,95,95, + 208,235,235,235,235,215,186,186,186,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,125,16,16,16,98,192, + 235,235,235,232,166,150,150,168,235,235,235,235,235,235,220,192, + 186,186,186,235,235,235,235,235,235,235,235,206,147,134,134,134, + 134,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,206,147,134,134,147,197,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,182,95,95,130, + 235,235,235,235,235,235,186,186,186,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,85,16,16,30,208, + 235,235,235,235,219,152,150,150,216,235,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,216,179,160, + 197,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,130,95,95,178, + 235,235,235,235,235,235,186,186,186,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,221,44,16,16,64, + 235,235,235,235,235,184,150,150,190,235,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,182,95,95,95,222, + 235,235,235,235,235,235,186,186,186,234,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,187,23,16,16, + 132,235,235,235,235,214,150,150,150,184,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,169,95, + 152,235,235,235,235,235,235,235,235,235,222,103,95,95,152,235, + 235,235,235,235,235,235,191,186,186,203,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,125,16,16, + 23,201,235,235,235,235,158,150,150,152,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,99,95, + 95,235,235,235,235,235,235,235,235,235,143,95,95,113,231,235, + 235,235,235,235,235,235,215,186,186,186,234,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,228,57,16, + 16,64,228,235,235,235,208,160,160,203,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,95,95, + 95,95,152,235,235,235,235,235,235,191,99,95,95,200,235,235, + 235,235,235,235,235,235,235,191,186,186,203,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,194,23, + 16,16,78,228,235,235,235,235,235,235,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,108,95, + 95,95,95,95,95,95,95,95,95,95,95,95,99,235,235,235, + 235,235,235,235,235,235,235,215,186,186,186,234,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,139, + 16,16,16,78,228,235,235,235,235,235,235,235,235,235,235,235, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,196,113, + 95,95,95,95,95,95,95,95,95,95,95,99,169,235,235,235, + 235,235,235,235,235,235,235,235,191,186,186,200,234,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 125,16,16,16,78,235,235,235,235,235,235,235,235,235,235,234, + 186,186,186,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 196,113,95,95,95,95,95,95,95,113,157,222,235,235,235,235, + 235,235,235,235,235,235,235,235,215,186,186,186,200,234,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,125,16,16,16,187,235,235,235,235,235,235,235,235,234,200, + 186,186,188,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,211,186,186,186,200,234,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,99,16,16,119,235,235,235,235,235,235,235,234,200,186, + 186,186,212,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,211,186,186,186,192,217, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,180,16,16,44,228,235,235,235,235,235,235,208,186,186, + 186,211,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,211,186,186,186,186, + 200,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,37,16,16,78,228,234,205,186,186,186,186,186,186, + 211,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,215,190,186,186, + 186,220,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,234,128,16,16,16,64,181,186,186,186,186,186,186,188, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,232,203,186, + 186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, + 186,186,186,186,101,16,16,16,64,181,186,186,186,186,192,217, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,231,188, + 186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, + 186,186,186,186,186,101,16,16,16,66,209,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,220, + 192,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, + 186,186,186,192,215,235,125,16,16,16,78,228,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,125,16,16,16,78,228,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,125,16,16,16,78,228,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,125,16,16,16,78,228,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,125,16,16,16,78,228, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,125,16,16,16,78, + 228,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,125,16,16,16, + 78,228,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,125,16,16, + 16,78,228,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,125,16, + 16,16,16,16,105,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,125, + 16,16,16,16,23,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 153,44,16,44,153,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,136,128,136,128,136,128,136,128,136,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 112,145,99,159,99,159,83,176,81,153,88,131,101,84,105,73, + 133,114,144,129,144,129,144,129,131,138,123,143,123,143,121,143, + 115,143,115,143,127,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,133,121,152,95,155,90,155,90,155,90, + 155,90,155,90,155,90,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,122,135, + 107,152,118,140,128,128,111,147,103,158,103,158,103,158,107,153, + 115,143,122,135,128,128,128,128,128,128,112,145,94,165,74,186, + 71,190,71,190,71,190,87,138,105,73,105,73,110,85,120,100, + 144,129,120,147,88,131,100,120,103,158,103,158,103,158,103,158, + 103,158,103,158,103,158,103,158,107,153,115,143,127,128,128,128, + 128,128,133,121,153,94,183,52,183,52,183,52,183,52,183,52, + 183,52,183,52,179,57,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,103,157, + 103,158,115,143,128,128,128,128,115,143,115,143,115,143,104,156, + 103,158,103,158,115,143,128,128,122,135,84,175,73,187,92,167, + 111,146,128,128,110,85,105,73,111,87,128,128,128,128,144,129, + 144,129,116,140,88,172,103,158,95,166,88,148,115,99,106,76, + 112,83,127,120,123,143,121,143,104,156,103,158,117,139,164,78, + 183,52,183,52,183,52,167,73,135,118,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,103,158, + 103,158,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,124,132,93,167,108,151,125,131,128,128,128,128,128,128, + 128,128,108,81,105,73,111,88,128,128,128,128,128,128,144,129, + 135,128,118,139,103,158,109,150,99,159,71,190,79,181,117,139, + 128,126,130,118,147,137,144,129,156,135,166,89,183,52,181,53, + 147,100,152,95,135,118,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,123,161, + 128,162,128,162,128,162,128,128,128,135,128,162,128,159,128,142, + 128,128,128,128,71,190,71,190,109,150,122,135,128,128,127,128, + 127,125,105,73,121,111,128,128,128,128,128,128,131,128,144,129, + 118,139,103,158,109,150,128,128,128,128,113,143,74,187,113,175, + 154,161,154,161,159,126,170,78,183,52,181,52,157,88,122,152, + 103,158,103,158,121,142,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,157,128,162, + 115,160,115,160,128,145,128,129,128,128,128,145,128,153,128,162, + 128,159,128,145,99,176,89,180,128,128,117,141,123,133,128,128, + 128,128,124,118,128,128,128,128,128,128,128,128,144,129,129,140, + 103,158,109,150,128,128,128,128,128,128,128,128,147,155,159,140, + 171,96,179,58,183,52,180,55,164,88,130,103,108,80,128,128, + 117,142,114,156,103,158,108,152,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,137,128,158,128,162,128,136, + 104,156,103,158,124,133,128,128,128,128,128,128,128,128,128,136, + 128,153,128,162,128,162,128,162,128,162,128,156,128,143,110,142, + 113,146,128,128,128,128,127,128,128,128,127,128,117,148,103,158, + 109,150,128,128,128,128,128,128,128,128,160,119,176,78,183,52, + 179,56,140,104,124,128,128,128,143,129,144,129,105,73,124,119, + 128,128,129,129,121,157,103,158,109,157,127,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,162,128,161,128,136,128,128, + 124,132,103,157,103,158,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,71,190,120,151,128,145,128,159,128,162,128,162, + 123,153,127,144,128,128,125,131,123,133,107,153,123,161,128,162, + 128,162,128,162,131,155,155,107,180,58,183,52,176,61,152,95, + 123,133,81,179,71,190,128,128,131,128,144,129,105,73,107,78, + 128,128,128,128,128,128,124,140,103,158,106,153,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,162,128,134,128,128,128,128, + 128,128,124,133,103,158,115,149,135,129,128,128,128,128,128,128, + 128,128,128,128,71,190,128,128,128,128,128,128,128,131,115,111, + 127,152,128,162,128,153,128,130,128,128,123,154,135,148,140,127, + 151,113,163,91,183,52,183,52,168,81,145,127,128,143,114,173, + 119,155,125,131,71,190,86,172,128,128,144,129,123,117,105,73, + 128,128,128,128,128,128,128,128,141,160,103,158,106,154,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,138,128,162,128,128,128,128,128,128, + 128,128,128,128,116,143,103,158,110,153,134,128,128,128,128,128, + 128,128,128,128,71,190,128,128,128,128,128,128,123,115,105,73, + 128,155,128,162,128,162,131,155,155,90,179,57,183,52,183,52, + 183,52,176,60,158,86,155,137,154,161,128,152,128,162,124,170, + 100,218,100,219,102,156,71,190,119,137,144,129,128,128,105,73, + 128,128,128,128,128,128,128,128,154,161,114,144,103,158,123,133, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,161,128,162,128,128,128,128,128,128, + 128,128,128,128,128,128,113,146,103,158,121,145,129,128,128,128, + 134,128,128,128,71,190,128,128,128,128,128,128,109,81,116,118, + 129,158,142,121,158,85,183,52,183,52,168,72,148,100,140,128, + 131,153,118,160,116,159,139,161,131,159,125,131,128,137,128,162, + 124,170,100,219,128,128,71,189,76,184,144,129,128,128,105,73, + 128,128,128,128,128,128,128,128,154,161,128,128,104,157,103,158, + 124,133,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,162,128,152,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,111,148,103,158,123,142,128,128, + 130,128,139,128,84,178,128,128,128,128,128,128,146,102,168,81, + 183,52,183,52,180,55,159,98,137,143,128,128,130,128,128,128, + 128,147,128,162,128,162,128,162,127,161,121,161,114,159,113,154, + 128,162,105,196,128,128,112,144,71,190,144,129,128,128,105,73, + 128,128,128,128,128,128,128,128,151,157,128,128,127,129,103,157, + 105,155,127,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,162,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,110,149,103,158,111,148, + 128,128,135,128,144,129,137,128,150,97,178,60,183,52,169,67, + 147,100,131,122,128,128,128,162,128,156,128,128,143,129,132,128, + 128,128,128,155,128,161,147,161,128,147,128,155,128,162,126,161, + 128,162,125,161,115,143,127,128,71,190,144,129,128,128,105,73, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,123,134, + 103,158,107,153,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,162,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,113,146,103,158, + 120,137,143,106,165,85,180,57,183,52,171,76,133,128,103,158, + 110,150,128,128,128,153,128,162,128,131,128,128,131,128,144,129, + 128,128,128,128,128,150,131,161,128,128,128,128,128,136,128,154, + 128,162,128,162,123,161,117,155,81,180,144,129,128,128,105,73, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 104,156,103,158,119,138,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,142,128,162,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,131,122, + 172,67,183,52,180,55,162,87,143,131,125,159,103,158,120,135, + 129,128,128,128,128,162,128,162,128,128,128,128,128,128,131,128, + 133,128,125,131,128,128,128,162,128,157,99,159,99,159,85,204, + 81,192,128,162,128,162,128,162,128,162,128,162,117,128,105,74, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 124,133,104,156,103,158,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,161,128,162,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,147,102,171,68,183,52, + 178,58,129,124,128,128,127,134,128,162,103,158,113,150,144,129, + 143,128,135,128,128,162,128,162,74,186,71,190,71,190,71,190, + 71,190,73,187,128,128,131,137,128,162,91,180,81,153,88,131, + 88,131,128,162,128,162,130,125,136,145,124,153,128,162,120,154, + 127,131,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,123,134,103,158,127,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,162,128,162,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,129,127,156,89,183,52,172,66,152,93, + 129,127,124,133,120,137,128,128,128,149,106,154,128,128,116,97, + 133,114,144,129,128,162,128,162,92,167,99,159,99,159,99,159, + 99,159,107,150,125,131,128,128,126,153,128,162,104,115,104,115, + 104,115,128,162,128,162,123,143,123,143,105,119,116,159,127,161, + 127,161,123,144,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,103,158,107,153,128,128,128,128,128,128,128,128, + 128,128,128,128,128,162,128,162,128,128,128,128,128,128,128,128, + 128,128,128,128,151,96,183,52,183,52,166,74,128,128,128,128, + 128,128,128,128,108,152,128,135,128,128,103,157,111,148,126,129, + 84,155,112,102,128,162,128,162,139,128,133,128,128,128,120,137, + 107,152,103,158,103,158,125,131,127,128,128,161,113,159,103,158, + 103,158,128,162,128,162,103,158,103,158,103,158,103,158,106,158, + 124,161,128,162,124,159,127,143,128,132,128,128,128,128,128,128, + 128,128,128,128,103,158,103,158,128,128,128,128,128,128,128,128, + 128,128,128,128,128,162,128,162,128,128,128,128,128,128,128,128, + 129,127,174,64,183,52,175,81,152,129,141,144,141,144,136,139, + 128,128,108,152,103,158,128,160,128,128,124,132,103,158,101,160, + 85,176,111,146,128,162,128,162,142,126,143,129,114,142,103,158, + 104,156,112,134,128,159,143,157,128,128,128,133,129,160,144,129, + 135,142,128,162,128,162,128,128,128,128,128,128,127,129,117,141, + 114,144,114,159,122,161,128,162,128,162,124,145,127,128,128,128, + 128,128,128,128,103,158,103,158,128,128,128,128,128,128,128,128, + 128,128,128,128,128,160,128,162,128,128,128,128,128,128,136,116, + 175,63,183,52,162,128,154,161,154,161,154,161,154,161,154,161, + 149,160,103,158,125,157,128,162,128,155,128,128,106,151,97,164, + 103,158,103,158,128,162,128,162,123,112,112,151,103,158,115,149, + 105,73,123,106,154,161,147,151,137,129,128,128,128,149,131,144, + 128,128,128,162,128,162,121,149,128,128,128,128,128,128,128,128, + 128,128,123,133,115,143,113,148,122,161,128,162,128,162,114,159, + 114,149,128,128,103,158,103,158,128,128,128,128,128,128,128,128, + 128,128,128,128,128,135,128,162,128,157,128,128,149,100,183,52, + 182,53,161,133,151,157,128,128,128,128,128,128,128,128,137,145, + 103,158,103,158,154,161,128,162,154,161,136,138,128,128,138,141, + 135,152,116,159,128,162,128,162,108,151,103,158,105,132,144,129, + 132,111,154,161,147,153,139,128,144,129,128,128,128,128,128,149, + 128,128,128,162,128,162,100,217,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,127,129,122,150,121,161,128,162, + 128,162,120,160,103,158,103,157,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,136,128,162,128,155,183,52,169,71, + 130,124,154,161,134,136,128,128,128,128,128,128,128,128,107,153, + 103,158,122,135,128,131,128,162,85,174,71,190,113,144,128,128, + 144,148,154,161,129,161,128,162,103,158,103,158,140,137,146,141, + 144,129,147,139,131,122,144,129,139,128,128,128,128,129,128,128, + 128,128,128,162,128,162,100,219,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,119,141, + 127,145,128,162,103,158,111,148,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,144,113,183,52,183,52,128,128, + 128,128,154,161,128,128,128,128,128,128,128,128,110,149,103,158, + 117,141,128,128,128,155,128,162,128,128,88,171,71,190,113,143, + 128,128,128,128,118,135,128,162,112,159,103,158,106,158,132,159, + 149,145,144,129,144,129,145,134,127,127,128,128,128,128,128,131, + 128,128,128,155,128,147,100,219,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,141,110,155,90,178,59, + 174,64,128,140,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,182,53,182,53,139,139,128,157, + 128,145,152,161,128,128,128,128,128,128,127,128,103,158,103,157, + 128,128,128,128,128,162,128,162,128,128,128,128,113,143,83,176, + 125,131,128,128,103,156,122,161,128,162,128,148,116,159,103,158, + 106,157,129,139,144,129,148,143,151,156,140,143,131,132,128,142, + 128,129,128,128,128,129,100,219,128,128,128,128,128,128,128,128, + 128,128,136,116,155,90,155,90,183,52,183,52,183,52,171,68, + 138,113,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,129,127,183,52,141,110,128,136,128,159, + 128,162,128,161,128,145,128,138,128,128,109,151,103,158,101,204, + 100,219,100,219,128,162,128,162,109,190,123,145,128,128,128,128, + 86,173,128,128,123,133,111,148,130,161,128,161,147,153,131,136, + 112,151,103,158,123,144,129,139,147,143,154,161,154,161,151,157, + 128,160,145,107,155,90,141,135,155,90,155,90,155,90,171,68, + 183,52,183,52,183,52,183,52,179,57,155,90,138,113,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,172,66,183,52,128,128,128,128,128,128, + 128,130,135,161,128,162,128,162,128,145,115,160,112,157,100,219, + 114,173,114,173,128,162,128,162,101,216,100,219,109,190,127,129, + 119,138,120,138,128,128,133,139,152,161,128,162,129,157,144,129, + 137,128,111,148,103,158,103,158,136,134,143,109,166,104,169,105, + 183,52,183,52,183,52,183,52,183,52,183,52,183,52,172,67, + 155,90,152,95,130,124,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,183,52,152,95,128,128,128,128,128,128, + 128,128,154,161,128,133,128,153,128,162,128,162,128,162,126,165, + 128,145,128,142,128,162,128,162,127,131,114,173,100,219,107,184, + 103,158,103,158,133,134,128,128,124,158,113,153,128,162,130,157, + 128,134,128,128,127,129,116,141,155,88,183,52,183,52,183,52, + 166,84,152,114,138,172,128,129,128,128,143,146,144,148,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,129,127,183,52,128,128,128,128,128,128,128,128, + 128,128,154,161,128,128,127,128,103,158,113,145,128,137,121,175, + 128,162,128,162,128,162,128,162,128,143,128,132,117,163,103,158, + 105,159,141,159,152,157,128,128,128,128,92,172,140,137,145,127, + 155,107,164,82,183,52,183,52,181,53,145,101,118,148,128,162, + 128,162,128,162,104,205,130,130,128,128,128,128,135,136,153,159, + 144,148,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,170,70,183,52,128,128,128,128,128,128,128,128, + 128,128,154,161,137,139,109,151,103,158,127,129,128,128,118,157, + 100,219,118,169,128,145,128,162,128,162,128,162,128,162,128,162, + 128,162,128,162,128,162,128,138,155,90,183,52,183,52,183,52, + 183,52,179,59,158,101,152,114,130,156,128,162,128,162,127,161, + 106,197,128,162,125,136,128,128,128,128,128,128,128,128,133,134, + 145,150,150,156,136,138,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,183,52,183,52,128,128,128,128,128,128,128,128, + 128,128,154,161,154,161,103,158,106,154,128,128,128,128,128,128, + 107,196,100,219,123,142,128,160,128,162,128,162,124,161,130,161, + 127,169,150,116,171,76,183,52,183,52,179,57,155,90,133,117, + 99,176,99,176,127,156,128,162,128,162,128,162,126,160,106,157, + 103,158,128,162,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,136,138,141,144,154,160,138,140,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,183,52,183,52,128,128,128,128,128,128,128,128, + 128,128,145,149,139,160,103,158,122,135,128,128,128,128,128,128, + 128,128,100,217,101,188,103,163,119,160,143,131,159,98,174,69, + 183,52,183,52,172,67,159,85,152,113,128,127,128,128,128,128, + 104,154,71,190,79,181,122,162,120,178,126,165,128,162,128,160, + 116,156,128,162,103,154,112,146,126,129,128,128,128,128,128,128, + 128,128,128,128,128,128,130,130,141,144,138,140,136,138,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,183,52,183,52,128,128,128,128,128,128,128,128, + 128,128,128,128,104,158,103,158,137,139,128,128,128,128,128,128, + 128,128,140,114,165,75,183,52,183,52,183,52,179,60,159,99, + 153,112,135,146,128,149,139,139,134,115,111,87,128,128,128,128, + 128,128,100,182,71,190,79,198,100,219,106,197,126,141,128,154, + 128,162,128,162,109,135,103,156,103,156,117,129,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,132,133,152,158, + 137,140,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,183,52,183,52,128,128,128,128,128,128,128,128, + 128,128,128,128,103,158,131,158,154,161,162,130,168,106,171,96, + 181,59,183,52,172,74,168,106,155,90,135,135,105,203,100,219, + 106,205,117,185,129,159,128,162,128,162,123,142,127,138,128,128, + 124,141,104,211,92,188,71,190,95,166,128,128,128,128,128,128, + 128,142,141,135,142,129,122,123,105,150,103,158,111,148,127,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 143,146,149,154,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,183,52,183,52,128,128,128,128,128,128,128,128, + 128,128,128,128,111,148,155,99,180,62,183,52,183,52,179,57, + 153,92,127,126,141,144,133,134,128,128,128,128,128,128,128,128, + 100,219,100,219,144,129,139,138,128,145,128,153,126,154,128,129, + 128,128,128,149,128,162,119,165,108,171,123,150,128,145,128,145, + 128,134,134,128,144,129,130,128,128,128,115,143,103,158,106,153, + 127,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,129,129,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,180,55,183,52,155,90,155,90,164,78,183,52, + 183,52,183,52,183,52,183,52,171,68,144,105,128,128,109,151, + 103,158,125,131,128,128,128,128,128,128,128,128,128,128,128,128, + 100,219,100,219,144,129,144,129,128,128,128,128,126,123,109,85, + 123,117,128,128,128,145,128,150,126,158,128,162,128,162,128,162, + 128,162,128,162,131,154,144,129,134,128,128,128,122,135,103,158, + 104,156,118,140,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,135,117,179,57,183,52,183,52,179,57,158,86, + 155,90,155,90,138,111,135,118,128,128,128,128,128,128,103,158, + 103,157,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 100,219,100,219,144,129,144,129,128,128,128,128,128,128,125,122, + 109,84,128,128,128,128,128,128,128,128,108,149,71,190,87,172, + 128,142,128,145,129,134,141,129,144,129,128,128,128,128,123,134, + 109,150,103,158,110,150,127,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,103,158,128,128,128,128,128,128,120,137,103,158, + 122,135,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 100,219,100,219,144,129,144,129,128,128,128,128,128,128,128,128, + 128,128,113,91,128,128,127,125,128,128,128,128,99,159,71,190, + 106,151,128,128,128,128,129,128,144,129,138,128,128,128,128,128, + 128,128,118,140,103,158,106,153,127,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,103,158,128,128,128,128,128,128,103,157,106,154, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 100,219,100,219,144,129,144,129,128,128,128,128,128,128,128,128, + 128,128,126,123,121,112,128,128,117,102,128,128,128,128,85,174, + 71,190,106,151,128,128,128,128,138,128,144,129,138,128,128,128, + 128,128,128,128,122,135,103,158,106,153,127,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,103,158,127,128,128,128,119,138,103,158,122,135, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 100,219,104,205,143,129,144,129,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,127,127,128,128,113,90,127,127,128,128, + 85,174,71,190,106,151,128,128,128,128,138,128,144,129,137,128, + 128,128,128,128,128,128,122,135,103,158,106,153,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,103,158,106,153,128,128,103,158,107,153,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,116,168, + 100,219,125,136,133,128,144,129,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,124,120,109,81,127,127, + 128,128,82,177,71,190,128,128,128,128,128,128,139,128,144,129, + 130,128,128,128,128,128,128,128,122,135,103,158,110,149,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,122,135,103,158,108,152,103,158,125,131,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,100,219, + 104,205,128,128,128,128,144,129,133,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,125,122,105,73, + 128,128,125,131,71,190,86,172,128,128,128,128,128,128,144,129, + 144,129,133,128,128,128,128,128,128,128,115,143,103,158,108,152, + 119,138,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,113,146,103,158,104,156,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,122,148,100,219, + 125,136,128,128,128,128,144,129,144,129,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,121,111, + 128,128,128,128,99,159,71,190,122,135,128,128,128,128,130,128, + 144,129,144,129,128,128,128,128,128,128,128,128,117,141,108,151, + 111,148,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,103,207,100,219, + 128,128,128,128,128,128,144,129,144,129,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,71,190,84,175,128,128,128,128,128,128, + 144,129,144,129,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,108,193, + 105,200,128,128,128,128,128,128,128,128,117,162,100,219,119,156, + 128,128,128,128,128,128,139,128,144,129,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,93,165,74,186,128,128,128,128,128,128, + 144,129,144,129,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,101,215, + 100,219,105,200,114,173,114,173,114,173,100,217,100,217,128,128, + 128,128,128,128,128,128,128,128,144,129,141,129,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 144,129,144,129,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,124,141, + 110,186,100,219,100,219,100,219,100,219,106,199,121,149,128,128, + 128,128,128,128,128,128,128,128,139,128,144,129,134,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 144,129,144,129,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,140,128,144,129,135,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,142,129, + 144,129,131,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,139,128,144,129, + 142,129,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,136,128,144,129,144,129,144,129, + 132,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,134,128, + 144,129,144,129,144,129,144,129,144,129,144,129,144,129,144,129, + 144,129,144,129,140,129,128,128,130,128,139,128,136,128,135,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 135,128,136,128,136,128,136,128,136,128,136,128,136,128,136,128, + 136,128,136,128,131,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +};
\ No newline at end of file |