1 //
2 // Copyright 2020 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 
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9 #include "util/EGLWindow.h"
10 #include "util/OSPixmap.h"
11 #include "util/OSWindow.h"
12 
13 #include <iostream>
14 
15 using namespace angle;
16 
17 class PixmapTest : public ANGLETest
18 {
19   protected:
PixmapTest()20     PixmapTest()
21     {
22         setWindowWidth(512);
23         setWindowHeight(512);
24         setConfigRedBits(8);
25         setConfigGreenBits(8);
26         setConfigBlueBits(8);
27         setConfigAlphaBits(8);
28     }
29 
testSetUp()30     void testSetUp() override
31     {
32         mTextureProgram =
33             CompileProgram(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
34         if (mTextureProgram == 0)
35         {
36             FAIL() << "shader compilation failed.";
37         }
38 
39         mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "u_tex2D");
40         ASSERT_NE(-1, mTextureUniformLocation);
41 
42         EGLWindow *window = getEGLWindow();
43 
44         EGLint surfaceType = 0;
45         eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_SURFACE_TYPE,
46                            &surfaceType);
47         mSupportsPixmaps = (surfaceType & EGL_PIXMAP_BIT) != 0;
48 
49         EGLint bindToTextureRGBA = 0;
50         eglGetConfigAttrib(window->getDisplay(), window->getConfig(), EGL_BIND_TO_TEXTURE_RGBA,
51                            &bindToTextureRGBA);
52         mSupportsBindTexImage =
53             IsEGLDisplayExtensionEnabled(window->getDisplay(), "EGL_NOK_texture_from_pixmap") &&
54             (bindToTextureRGBA == EGL_TRUE);
55 
56         if (mSupportsPixmaps)
57         {
58             mOSPixmap.reset(CreateOSPixmap());
59 
60             OSWindow *osWindow = getOSWindow();
61 
62             EGLint nativeVisual = 0;
63             ASSERT_TRUE(eglGetConfigAttrib(window->getDisplay(), window->getConfig(),
64                                            EGL_NATIVE_VISUAL_ID, &nativeVisual));
65             ASSERT_TRUE(mOSPixmap->initialize(osWindow->getNativeDisplay(), mPixmapSize,
66                                               mPixmapSize, nativeVisual));
67 
68             std::vector<EGLint> attribs;
69             if (mSupportsBindTexImage)
70             {
71                 attribs.push_back(EGL_TEXTURE_FORMAT);
72                 attribs.push_back(EGL_TEXTURE_RGBA);
73 
74                 attribs.push_back(EGL_TEXTURE_TARGET);
75                 attribs.push_back(EGL_TEXTURE_2D);
76             }
77 
78             attribs.push_back(EGL_NONE);
79 
80             mPixmap = eglCreatePixmapSurface(window->getDisplay(), window->getConfig(),
81                                              mOSPixmap->getNativePixmap(), attribs.data());
82             ASSERT_NE(mPixmap, EGL_NO_SURFACE);
83             ASSERT_EGL_SUCCESS();
84         }
85 
86         ASSERT_GL_NO_ERROR();
87     }
88 
testTearDown()89     void testTearDown() override
90     {
91         glDeleteProgram(mTextureProgram);
92 
93         if (mPixmap)
94         {
95             EGLWindow *window = getEGLWindow();
96             eglDestroySurface(window->getDisplay(), mPixmap);
97         }
98 
99         mOSPixmap = nullptr;
100     }
101 
102     GLuint mTextureProgram;
103     GLint mTextureUniformLocation;
104 
105     std::unique_ptr<OSPixmap> mOSPixmap;
106     EGLSurface mPixmap = EGL_NO_SURFACE;
107 
108     const size_t mPixmapSize = 32;
109     bool mSupportsPixmaps;
110     bool mSupportsBindTexImage;
111 };
112 
113 // Test clearing a Pixmap and checking the color is correct
TEST_P(PixmapTest,Clearing)114 TEST_P(PixmapTest, Clearing)
115 {
116     ANGLE_SKIP_TEST_IF(!mSupportsPixmaps);
117 
118     EGLWindow *window = getEGLWindow();
119 
120     // Clear the window surface to blue and verify
121     window->makeCurrent();
122     ASSERT_EGL_SUCCESS();
123 
124     glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
125     glClear(GL_COLOR_BUFFER_BIT);
126     ASSERT_GL_NO_ERROR();
127     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
128 
129     // Apply the Pixmap and clear it to purple and verify
130     eglMakeCurrent(window->getDisplay(), mPixmap, mPixmap, window->getContext());
131     ASSERT_EGL_SUCCESS();
132 
133     glViewport(0, 0, static_cast<GLsizei>(mPixmapSize), static_cast<GLsizei>(mPixmapSize));
134     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
135     glClear(GL_COLOR_BUFFER_BIT);
136     ASSERT_GL_NO_ERROR();
137     EXPECT_PIXEL_EQ(static_cast<GLint>(mPixmapSize) / 2, static_cast<GLint>(mPixmapSize) / 2, 255,
138                     0, 255, 255);
139 
140     // Rebind the window surface and verify that it is still blue
141     window->makeCurrent();
142     ASSERT_EGL_SUCCESS();
143     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
144 }
145 
146 // Bind the Pixmap to a texture and verify it renders correctly
TEST_P(PixmapTest,BindTexImage)147 TEST_P(PixmapTest, BindTexImage)
148 {
149     // Test skipped because pixmaps are not supported or pixmaps do not support binding to RGBA
150     // textures.
151     ANGLE_SKIP_TEST_IF(!mSupportsPixmaps || !mSupportsBindTexImage);
152 
153     // This test fails flakily on Linux intel when run with many other tests.
154     ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel());
155 
156     EGLWindow *window = getEGLWindow();
157 
158     // Apply the Pixmap and clear it to purple
159     eglMakeCurrent(window->getDisplay(), mPixmap, mPixmap, window->getContext());
160     ASSERT_EGL_SUCCESS();
161 
162     glViewport(0, 0, static_cast<GLsizei>(mPixmapSize), static_cast<GLsizei>(mPixmapSize));
163     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
164     glClear(GL_COLOR_BUFFER_BIT);
165     ASSERT_GL_NO_ERROR();
166 
167     EXPECT_PIXEL_EQ(static_cast<GLint>(mPixmapSize) / 2, static_cast<GLint>(mPixmapSize) / 2, 255,
168                     0, 255, 255);
169 
170     // Apply the window surface
171     window->makeCurrent();
172 
173     // Create a texture and bind the pixmap to it
174     GLuint texture = 0;
175     glGenTextures(1, &texture);
176     glBindTexture(GL_TEXTURE_2D, texture);
177     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
178     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
179     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
180     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
181     EXPECT_GL_NO_ERROR();
182 
183     eglBindTexImage(window->getDisplay(), mPixmap, EGL_BACK_BUFFER);
184     glViewport(0, 0, getWindowWidth(), getWindowHeight());
185     ASSERT_EGL_SUCCESS();
186 
187     // Draw a quad and verify that it is purple
188     glUseProgram(mTextureProgram);
189     glUniform1i(mTextureUniformLocation, 0);
190 
191     drawQuad(mTextureProgram, essl31_shaders::PositionAttrib(), 0.5f);
192     EXPECT_GL_NO_ERROR();
193 
194     // Unbind the texture
195     eglReleaseTexImage(window->getDisplay(), mPixmap, EGL_BACK_BUFFER);
196     ASSERT_EGL_SUCCESS();
197 
198     // Verify that purple was drawn
199     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
200 
201     glDeleteTextures(1, &texture);
202 }
203 
204 // Bind a Pixmap, redefine the texture, and verify it renders correctly
TEST_P(PixmapTest,BindTexImageAndRedefineTexture)205 TEST_P(PixmapTest, BindTexImageAndRedefineTexture)
206 {
207     // Test skipped because pixmaps are not supported or Pixmaps do not support binding to RGBA
208     // textures.
209     ANGLE_SKIP_TEST_IF(!mSupportsPixmaps || !mSupportsBindTexImage);
210 
211     EGLWindow *window = getEGLWindow();
212 
213     // Apply the Pixmap and clear it to purple
214     eglMakeCurrent(window->getDisplay(), mPixmap, mPixmap, window->getContext());
215     ASSERT_EGL_SUCCESS();
216 
217     glViewport(0, 0, static_cast<GLsizei>(mPixmapSize), static_cast<GLsizei>(mPixmapSize));
218     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
219     glClear(GL_COLOR_BUFFER_BIT);
220     ASSERT_GL_NO_ERROR();
221 
222     EXPECT_PIXEL_EQ(static_cast<GLint>(mPixmapSize) / 2, static_cast<GLint>(mPixmapSize) / 2, 255,
223                     0, 255, 255);
224 
225     // Apply the window surface
226     window->makeCurrent();
227 
228     // Create a texture and bind the Pixmap to it
229     GLuint texture = 0;
230     glGenTextures(1, &texture);
231     glBindTexture(GL_TEXTURE_2D, texture);
232     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
233     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
234     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
235     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
236     EXPECT_GL_NO_ERROR();
237 
238     eglBindTexImage(window->getDisplay(), mPixmap, EGL_BACK_BUFFER);
239     glViewport(0, 0, getWindowWidth(), getWindowHeight());
240     ASSERT_EGL_SUCCESS();
241 
242     // Redefine the texture
243     unsigned int pixelValue = 0xFFFF00FF;
244     std::vector<unsigned int> pixelData(getWindowWidth() * getWindowHeight(), pixelValue);
245     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
246                  GL_UNSIGNED_BYTE, &pixelData[0]);
247 
248     // Draw a quad and verify that it is magenta
249     glUseProgram(mTextureProgram);
250     glUniform1i(mTextureUniformLocation, 0);
251 
252     drawQuad(mTextureProgram, essl31_shaders::PositionAttrib(), 0.5f);
253     EXPECT_GL_NO_ERROR();
254 
255     // Verify that magenta was drawn
256     EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
257 
258     glDeleteTextures(1, &texture);
259 }
260 
261 ANGLE_INSTANTIATE_TEST_ES2(PixmapTest);
262