| // | |
| // Copyright 2022 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. | |
| // | |
| // EGLImageMECFriendlyTest: | |
| // MEC friendly tests are tests that use all of the created resources, so that | |
| // MEC will have to capture everything, and we can test with capture/replay | |
| // whether this is done correctly. In this case the focus is on external images | |
| #include <array> | |
| #include "common/unsafe_buffers.h" | |
| #include "test_utils/ANGLETest.h" | |
| #include "test_utils/gl_raii.h" | |
| #include "util/EGLWindow.h" | |
| constexpr int kPixelThreshold = 1; | |
| namespace angle | |
| { | |
| class EGLImageMECFriendlyTest : public ANGLETest<> | |
| { | |
| protected: | |
| EGLImageMECFriendlyTest() | |
| { | |
| setWindowWidth(128); | |
| setWindowHeight(128); | |
| setConfigRedBits(8); | |
| setConfigGreenBits(8); | |
| setConfigBlueBits(8); | |
| setConfigAlphaBits(8); | |
| setConfigDepthBits(24); | |
| } | |
| void testSetUp() override | |
| { | |
| if (!IsGLExtensionEnabled("GL_OES_EGL_image_external")) | |
| { | |
| return; | |
| } | |
| constexpr GLsizei texSize = 32; | |
| std::array<GLubyte, texSize * texSize * 4> data; | |
| for (int y = 0; y < texSize; y++) | |
| { | |
| float green = static_cast<float>(y) / texSize; | |
| for (int x = 0; x < texSize; x++) | |
| { | |
| float blue = static_cast<float>(x) / texSize; | |
| data[(y * texSize + x) * 4 + 0] = 0; | |
| data[(y * texSize + x) * 4 + 1] = static_cast<GLubyte>(green * 255); | |
| data[(y * texSize + x) * 4 + 2] = static_cast<GLubyte>(blue * 255); | |
| data[(y * texSize + x) * 4 + 3] = 255; | |
| } | |
| } | |
| glGenTextures(1, &mSourceTexture); | |
| glBindTexture(GL_TEXTURE_2D, mSourceTexture); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, | |
| data.data()); | |
| glBindTexture(GL_TEXTURE_2D, 0); | |
| glGenTextures(1, &mExternalTexture); | |
| const char *vertSrc = R"(precision highp float; | |
| attribute vec4 a_position; | |
| varying vec2 v_texcoord; | |
| uniform vec2 u_offset; | |
| void main() | |
| { | |
| gl_Position = a_position; | |
| v_texcoord = (a_position.xy * 0.5) + 0.5 + u_offset; | |
| } | |
| )"; | |
| const char *fragSrc = R"(#extension GL_OES_EGL_image_external : require | |
| precision highp float; | |
| uniform samplerExternalOES s_tex; | |
| varying vec2 v_texcoord; | |
| void main() | |
| { | |
| gl_FragColor = texture2D(s_tex, v_texcoord); | |
| } | |
| )"; | |
| mProgram = CompileProgram(vertSrc, fragSrc); | |
| ASSERT_GL_NO_ERROR(); | |
| ASSERT_NE(mProgram, 0u); | |
| } | |
| void testTearDown() override | |
| { | |
| if (mExternalTexture != 0) | |
| { | |
| glDeleteTextures(1, &mExternalTexture); | |
| } | |
| if (mSourceTexture != 0) | |
| { | |
| glDeleteTextures(1, &mSourceTexture); | |
| } | |
| } | |
| void createExternalTexture() | |
| { | |
| ASSERT_TRUE(IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), | |
| "EGL_KHR_gl_texture_2D_image")); | |
| ASSERT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external")); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLint attribs[] = { | |
| EGL_IMAGE_PRESERVED, | |
| EGL_TRUE, | |
| EGL_NONE, | |
| }; | |
| EGLImageKHR image = eglCreateImageKHR( | |
| window->getDisplay(), window->getContext(), EGL_GL_TEXTURE_2D_KHR, | |
| reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(mSourceTexture)), attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture); | |
| glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); | |
| glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| GLuint mSourceTexture{0}; | |
| EGLImageKHR mExternalImage{nullptr}; | |
| GLuint mExternalTexture{0}; | |
| GLuint mProgram{0}; | |
| }; | |
| // Test the use of an external texture, make the test friendly for triggering MEC | |
| // that is - use all the created resources in all frames | |
| TEST_P(EGLImageMECFriendlyTest, DrawExternalTextureInLoop) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image_external")); | |
| ANGLE_SKIP_TEST_IF( | |
| !IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_gl_texture_2D_image")); | |
| // Ozone only supports external target for images created with EGL_EXT_image_dma_buf_import | |
| ANGLE_SKIP_TEST_IF(IsOzone()); | |
| createExternalTexture(); | |
| ASSERT_NE(mProgram, 0u); | |
| glUseProgram(mProgram); | |
| glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture); | |
| glUniform2f(glGetUniformLocation(mProgram, "u_offset"), 0.0, 0.0); | |
| for (int i = 0; i < 10; ++i) | |
| { | |
| glClearColor(i / 10.0, 0.0, 0.0, 1.0); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| drawQuad(mProgram, "a_position", 0); | |
| EXPECT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0, 0, 0, 255), kPixelThreshold); | |
| EXPECT_PIXEL_COLOR_NEAR(127, 0, GLColor(0, 0, 247, 255), kPixelThreshold); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 127, GLColor(0, 247, 0, 255), kPixelThreshold); | |
| EXPECT_PIXEL_COLOR_NEAR(127, 127, GLColor(0, 247, 247, 255), kPixelThreshold); | |
| swapBuffers(); | |
| } | |
| } | |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(EGLImageMECFriendlyTest); | |
| } // namespace angle |