1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // EGLImageMECFriendlyTest:
7 // MEC friendly tests are tests that use all of the created resources, so that
8 // MEC will have to capture everything, and we can test with capture/replay
9 // whether this is done correctly. In this case the focus is on external images
10
11 #include "test_utils/ANGLETest.h"
12 #include "test_utils/gl_raii.h"
13 #include "util/EGLWindow.h"
14
15 constexpr int kPixelThreshold = 1;
16
17 namespace angle
18 {
19 class EGLImageMECFriendlyTest : public ANGLETest<>
20 {
21 protected:
EGLImageMECFriendlyTest()22 EGLImageMECFriendlyTest()
23 {
24 setWindowWidth(128);
25 setWindowHeight(128);
26 setConfigRedBits(8);
27 setConfigGreenBits(8);
28 setConfigBlueBits(8);
29 setConfigAlphaBits(8);
30 setConfigDepthBits(24);
31 }
32
testSetUp()33 void testSetUp() override
34 {
35 if (!IsGLExtensionEnabled("GL_OES_EGL_image_external"))
36 {
37 return;
38 }
39
40 constexpr GLsizei texSize = 32;
41 GLubyte data[texSize * texSize * 4];
42
43 for (int y = 0; y < texSize; y++)
44 {
45 float green = static_cast<float>(y) / texSize;
46 for (int x = 0; x < texSize; x++)
47 {
48 float blue = static_cast<float>(x) / texSize;
49
50 data[(y * texSize + x) * 4 + 0] = 0;
51 data[(y * texSize + x) * 4 + 1] = static_cast<GLubyte>(green * 255);
52 data[(y * texSize + x) * 4 + 2] = static_cast<GLubyte>(blue * 255);
53 ;
54 data[(y * texSize + x) * 4 + 3] = 255;
55 }
56 }
57
58 glGenTextures(1, &mSourceTexture);
59 glBindTexture(GL_TEXTURE_2D, mSourceTexture);
60 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
61 data);
62 glBindTexture(GL_TEXTURE_2D, 0);
63 glGenTextures(1, &mExternalTexture);
64
65 const char *vertSrc = R"(precision highp float;
66 attribute vec4 a_position;
67 varying vec2 v_texcoord;
68
69 uniform vec2 u_offset;
70
71 void main()
72 {
73 gl_Position = a_position;
74 v_texcoord = (a_position.xy * 0.5) + 0.5 + u_offset;
75 }
76 )";
77 const char *fragSrc = R"(#extension GL_OES_EGL_image_external : require
78 precision highp float;
79 uniform samplerExternalOES s_tex;
80 varying vec2 v_texcoord;
81
82 void main()
83 {
84 gl_FragColor = texture2D(s_tex, v_texcoord);
85 }
86 )";
87
88 mProgram = CompileProgram(vertSrc, fragSrc);
89 ASSERT_GL_NO_ERROR();
90 ASSERT_NE(mProgram, 0u);
91 }
92
testTearDown()93 void testTearDown() override
94 {
95 if (mExternalTexture != 0)
96 {
97 glDeleteTextures(1, &mExternalTexture);
98 }
99 if (mSourceTexture != 0)
100 {
101 glDeleteTextures(1, &mSourceTexture);
102 }
103 }
104
createExternalTexture()105 void createExternalTexture()
106 {
107 ASSERT_TRUE(IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
108 "EGL_KHR_gl_texture_2D_image"));
109 ASSERT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external"));
110
111 EGLWindow *window = getEGLWindow();
112 EGLint attribs[] = {
113 EGL_IMAGE_PRESERVED,
114 EGL_TRUE,
115 EGL_NONE,
116 };
117 EGLImageKHR image = eglCreateImageKHR(
118 window->getDisplay(), window->getContext(), EGL_GL_TEXTURE_2D_KHR,
119 reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(mSourceTexture)), attribs);
120 ASSERT_EGL_SUCCESS();
121
122 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
123 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
124
125 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
126 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
127
128 ASSERT_GL_NO_ERROR();
129 }
130 GLuint mSourceTexture{0};
131 EGLImageKHR mExternalImage{nullptr};
132 GLuint mExternalTexture{0};
133 GLuint mProgram{0};
134 };
135
136 // Test the use of an external texture, make the test friendly for triggering MEC
137 // that is - use all the created resources in all frames
TEST_P(EGLImageMECFriendlyTest,DrawExternalTextureInLoop)138 TEST_P(EGLImageMECFriendlyTest, DrawExternalTextureInLoop)
139 {
140 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image_external"));
141 ANGLE_SKIP_TEST_IF(
142 !IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_gl_texture_2D_image"));
143
144 // Ozone only supports external target for images created with EGL_EXT_image_dma_buf_import
145 ANGLE_SKIP_TEST_IF(IsOzone());
146
147 createExternalTexture();
148
149 ASSERT_NE(mProgram, 0u);
150 glUseProgram(mProgram);
151 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
152 glUniform2f(glGetUniformLocation(mProgram, "u_offset"), 0.0, 0.0);
153
154 for (int i = 0; i < 10; ++i)
155 {
156 glClearColor(i / 10.0, 0.0, 0.0, 1.0);
157 glClear(GL_COLOR_BUFFER_BIT);
158 drawQuad(mProgram, "a_position", 0);
159 EXPECT_GL_NO_ERROR();
160 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0, 0, 0, 255), kPixelThreshold);
161 EXPECT_PIXEL_COLOR_NEAR(127, 0, GLColor(0, 0, 247, 255), kPixelThreshold);
162 EXPECT_PIXEL_COLOR_NEAR(0, 127, GLColor(0, 247, 0, 255), kPixelThreshold);
163 EXPECT_PIXEL_COLOR_NEAR(127, 127, GLColor(0, 247, 247, 255), kPixelThreshold);
164 swapBuffers();
165 }
166 }
167
168 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(EGLImageMECFriendlyTest);
169 } // namespace angle
170