• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 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 // EGLProgramCacheControlTest:
7 //   Unit tests for the EGL_ANGLE_program_cache_control extension.
8 
9 #include "common/angleutils.h"
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12 #include "util/EGLWindow.h"
13 
14 using namespace angle;
15 
16 constexpr EGLint kEnabledCacheSize = 0x10000;
17 constexpr char kEGLExtName[]       = "EGL_ANGLE_program_cache_control";
18 
19 void TestCacheProgram(PlatformMethods *platform,
20                       const ProgramKeyType &key,
21                       size_t programSize,
22                       const uint8_t *programBytes);
23 
24 class EGLProgramCacheControlTest : public ANGLETest<>
25 {
26   public:
onCache(const ProgramKeyType & key,size_t programSize,const uint8_t * programBytes)27     void onCache(const ProgramKeyType &key, size_t programSize, const uint8_t *programBytes)
28     {
29         mCachedKey = key;
30         mCachedBinary.assign(&programBytes[0], &programBytes[programSize]);
31     }
32 
33   protected:
EGLProgramCacheControlTest()34     EGLProgramCacheControlTest()
35     {
36         // Test flakiness was noticed when reusing displays.
37         forceNewDisplay();
38         setDeferContextInit(true);
39         setContextProgramCacheEnabled(true);
40         gDefaultPlatformMethods.cacheProgram = TestCacheProgram;
41     }
42 
testSetUp()43     void testSetUp() override
44     {
45         if (extensionAvailable())
46         {
47             EGLDisplay display = getEGLWindow()->getDisplay();
48             eglProgramCacheResizeANGLE(display, kEnabledCacheSize, EGL_PROGRAM_CACHE_RESIZE_ANGLE);
49             ASSERT_EGL_SUCCESS();
50         }
51 
52         ASSERT_TRUE(getEGLWindow()->initializeContext());
53     }
54 
testTearDown()55     void testTearDown() override { gDefaultPlatformMethods.cacheProgram = DefaultCacheProgram; }
56 
extensionAvailable()57     bool extensionAvailable()
58     {
59         EGLDisplay display = getEGLWindow()->getDisplay();
60         return IsEGLDisplayExtensionEnabled(display, kEGLExtName);
61     }
62 
programBinaryAvailable()63     bool programBinaryAvailable()
64     {
65         return (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_OES_get_program_binary"));
66     }
67 
68     ProgramKeyType mCachedKey;
69     std::vector<uint8_t> mCachedBinary;
70 };
71 
TestCacheProgram(PlatformMethods * platform,const ProgramKeyType & key,size_t programSize,const uint8_t * programBytes)72 void TestCacheProgram(PlatformMethods *platform,
73                       const ProgramKeyType &key,
74                       size_t programSize,
75                       const uint8_t *programBytes)
76 {
77     auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
78     auto *testCase =
79         reinterpret_cast<EGLProgramCacheControlTest *>(testPlatformContext->currentTest);
80     testCase->onCache(key, programSize, programBytes);
81 }
82 
83 // Tests error conditions of the APIs.
TEST_P(EGLProgramCacheControlTest,NegativeAPI)84 TEST_P(EGLProgramCacheControlTest, NegativeAPI)
85 {
86     ANGLE_SKIP_TEST_IF(!extensionAvailable());
87 
88     constexpr char kDefaultKey[]        = "defaultMakeItLongEnough";
89     constexpr char kDefaultBinary[]     = "defaultMakeItLongEnough";
90     constexpr EGLint kDefaultKeySize    = static_cast<EGLint>(ArraySize(kDefaultKey));
91     constexpr EGLint kDefaultBinarySize = static_cast<EGLint>(ArraySize(kDefaultBinary));
92 
93     // Test that passing an invalid display to the entry point methods fails.
94     eglProgramCacheGetAttribANGLE(EGL_NO_DISPLAY, EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE);
95     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
96 
97     eglProgramCachePopulateANGLE(EGL_NO_DISPLAY, kDefaultKey, kDefaultKeySize, kDefaultBinary,
98                                  kDefaultBinarySize);
99     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
100 
101     EGLint tempKeySize    = 0;
102     EGLint tempBinarySize = 0;
103     eglProgramCacheQueryANGLE(EGL_NO_DISPLAY, 0, nullptr, &tempKeySize, nullptr, &tempBinarySize);
104     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
105 
106     eglProgramCacheResizeANGLE(EGL_NO_DISPLAY, 0, EGL_PROGRAM_CACHE_TRIM_ANGLE);
107     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
108 
109     // Test querying properties with bad parameters.
110     EGLDisplay display = getEGLWindow()->getDisplay();
111     eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_RESIZE_ANGLE);
112     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
113 
114     // Test populating with invalid parameters.
115     EGLint keySize = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE);
116     EXPECT_GT(kDefaultKeySize, keySize);
117     eglProgramCachePopulateANGLE(display, kDefaultKey, keySize + 1, kDefaultBinary,
118                                  kDefaultBinarySize);
119     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
120 
121     eglProgramCachePopulateANGLE(display, kDefaultKey, keySize, kDefaultBinary, -1);
122     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
123 
124     eglProgramCachePopulateANGLE(display, nullptr, keySize, kDefaultBinary, kDefaultBinarySize);
125     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
126 
127     eglProgramCachePopulateANGLE(display, kDefaultKey, keySize, nullptr, kDefaultBinarySize);
128     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
129 
130     // Test querying cache entries with invalid parameters.
131     eglProgramCachePopulateANGLE(display, kDefaultKey, keySize, kDefaultBinary, kDefaultBinarySize);
132     ASSERT_EGL_SUCCESS();
133 
134     EGLint cacheSize = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_SIZE_ANGLE);
135     ASSERT_EQ(1, cacheSize);
136 
137     eglProgramCacheQueryANGLE(display, -1, nullptr, &tempKeySize, nullptr, &tempBinarySize);
138     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
139 
140     eglProgramCacheQueryANGLE(display, 1, nullptr, &tempKeySize, nullptr, &tempBinarySize);
141     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
142 
143     eglProgramCacheQueryANGLE(display, 0, nullptr, nullptr, nullptr, &tempBinarySize);
144     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
145 
146     eglProgramCacheQueryANGLE(display, 0, nullptr, &tempKeySize, nullptr, nullptr);
147     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
148 
149     eglProgramCacheQueryANGLE(display, 0, nullptr, &tempKeySize, nullptr, &tempBinarySize);
150     ASSERT_EGL_SUCCESS();
151     ASSERT_EQ(keySize, tempKeySize);
152     ASSERT_EQ(kDefaultBinarySize, tempBinarySize);
153 
154     std::vector<uint8_t> tempKey(tempKeySize + 5);
155     std::vector<uint8_t> tempBinary(tempBinarySize + 5);
156 
157     tempKeySize--;
158 
159     eglProgramCacheQueryANGLE(display, 0, tempKey.data(), &tempKeySize, tempBinary.data(),
160                               &tempBinarySize);
161     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
162 
163     tempKeySize++;
164     tempBinarySize--;
165 
166     eglProgramCacheQueryANGLE(display, 0, tempKey.data(), &tempKeySize, tempBinary.data(),
167                               &tempBinarySize);
168     EXPECT_EGL_ERROR(EGL_BAD_ACCESS);
169 
170     // Test resizing with invalid parameters.
171     eglProgramCacheResizeANGLE(display, -1, EGL_PROGRAM_CACHE_TRIM_ANGLE);
172     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
173 
174     eglProgramCacheResizeANGLE(display, 0, EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE);
175     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
176 }
177 
178 // Tests a basic use case.
TEST_P(EGLProgramCacheControlTest,SaveAndReload)179 TEST_P(EGLProgramCacheControlTest, SaveAndReload)
180 {
181     ANGLE_SKIP_TEST_IF(getEGLWindow()->isFeatureEnabled(Feature::DisableProgramCaching));
182 
183     ANGLE_SKIP_TEST_IF(!extensionAvailable() || !programBinaryAvailable());
184 
185     constexpr char kVS[] = "attribute vec4 position; void main() { gl_Position = position; }";
186     constexpr char kFS[] = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
187 
188     mCachedBinary.clear();
189     // Link a program, which will miss the cache.
190     {
191         glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
192         glClear(GL_COLOR_BUFFER_BIT);
193         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
194 
195         ANGLE_GL_PROGRAM(program, kVS, kFS);
196         drawQuad(program, "position", 0.5f);
197         EXPECT_GL_NO_ERROR();
198         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
199     }
200     // Assert that the cache insertion added a program to the cache.
201     EXPECT_TRUE(!mCachedBinary.empty());
202 
203     EGLDisplay display = getEGLWindow()->getDisplay();
204 
205     EGLint keySize    = 0;
206     EGLint binarySize = 0;
207     eglProgramCacheQueryANGLE(display, 0, nullptr, &keySize, nullptr, &binarySize);
208     EXPECT_EQ(static_cast<EGLint>(mCachedKey.size()), keySize);
209     ASSERT_EGL_SUCCESS();
210 
211     ProgramKeyType keyBuffer;
212     std::vector<uint8_t> binaryBuffer(binarySize);
213     eglProgramCacheQueryANGLE(display, 0, keyBuffer.data(), &keySize, binaryBuffer.data(),
214                               &binarySize);
215     ASSERT_EGL_SUCCESS();
216 
217     EXPECT_EQ(mCachedKey, keyBuffer);
218     EXPECT_EQ(mCachedBinary, binaryBuffer);
219 
220     // Restart EGL and GL.
221     recreateTestFixture();
222 
223     // Warm up the cache.
224     EGLint newCacheSize = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_SIZE_ANGLE);
225     EXPECT_EQ(0, newCacheSize);
226     eglProgramCachePopulateANGLE(display, keyBuffer.data(), keySize, binaryBuffer.data(),
227                                  binarySize);
228 
229     mCachedBinary.clear();
230 
231     // Link a program, which will hit the cache.
232     {
233         glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
234         glClear(GL_COLOR_BUFFER_BIT);
235         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
236 
237         ANGLE_GL_PROGRAM(program, kVS, kFS);
238         drawQuad(program, "position", 0.5f);
239         EXPECT_GL_NO_ERROR();
240         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
241     }
242 
243     // Verify no new shader was compiled.
244     EXPECT_TRUE(mCachedBinary.empty());
245 }
246 
247 // Tests that trying to link a program without correct shaders doesn't buggily call the cache.
TEST_P(EGLProgramCacheControlTest,LinkProgramWithBadShaders)248 TEST_P(EGLProgramCacheControlTest, LinkProgramWithBadShaders)
249 {
250     ANGLE_SKIP_TEST_IF(!extensionAvailable());
251 
252     GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
253 
254     GLuint program = glCreateProgram();
255     glAttachShader(program, shader);
256     glLinkProgram(program);
257 
258     GLint linkStatus = 0;
259     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
260     EXPECT_GL_FALSE(linkStatus);
261     EXPECT_GL_NO_ERROR();
262 
263     glDeleteShader(shader);
264     glDeleteProgram(program);
265 }
266 
267 // Tests the program cache can be disabled.
TEST_P(EGLProgramCacheControlTest,DisableProgramCache)268 TEST_P(EGLProgramCacheControlTest, DisableProgramCache)
269 {
270     ANGLE_SKIP_TEST_IF(!extensionAvailable() || !programBinaryAvailable());
271 
272     // Disable context program cache, and recreate context.
273     setContextProgramCacheEnabled(false);
274     recreateTestFixture();
275 
276     constexpr char kVS[] = "attribute vec4 position; void main() { gl_Position = position; }";
277     constexpr char kFS[] = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
278 
279     mCachedBinary.clear();
280     // Link a program, which will miss the cache.
281     {
282         glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
283         glClear(GL_COLOR_BUFFER_BIT);
284         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
285 
286         ANGLE_GL_PROGRAM(program, kVS, kFS);
287         drawQuad(program, "position", 0.5f);
288         EXPECT_GL_NO_ERROR();
289         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
290     }
291 
292     // Expect that no program binary was inserted into the cache.
293     EXPECT_TRUE(mCachedBinary.empty());
294 }
295 
296 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLProgramCacheControlTest);
297 ANGLE_INSTANTIATE_TEST(EGLProgramCacheControlTest,
298                        ES2_D3D9(),
299                        ES2_D3D11(),
300                        ES2_OPENGL(),
301                        ES2_VULKAN());
302