// // 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 "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; GLubyte data[texSize * texSize * 4]; for (int y = 0; y < texSize; y++) { float green = static_cast(y) / texSize; for (int x = 0; x < texSize; x++) { float blue = static_cast(x) / texSize; data[(y * texSize + x) * 4 + 0] = 0; data[(y * texSize + x) * 4 + 1] = static_cast(green * 255); data[(y * texSize + x) * 4 + 2] = static_cast(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); 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(static_cast(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