• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 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 // EGLContextCompatibilityTest.cpp:
8 //   This test will try to use all combinations of context configs and
9 //   surface configs. If the configs are compatible, it checks that simple
10 //   rendering works, otherwise it checks an error is generated one MakeCurrent.
11 //
12 
13 #include <gtest/gtest.h>
14 
15 #include <unordered_set>
16 #include <vector>
17 
18 #include "common/debug.h"
19 #include "test_utils/ANGLETest.h"
20 #include "test_utils/angle_test_configs.h"
21 #include "test_utils/angle_test_instantiate.h"
22 #include "util/OSWindow.h"
23 #include "util/random_utils.h"
24 
25 using namespace angle;
26 
27 namespace
28 {
29 // The only configs with 16-bits for each of red, green, blue, and alpha is GL_RGBA16F
IsRGBA16FConfig(EGLDisplay display,EGLConfig config)30 bool IsRGBA16FConfig(EGLDisplay display, EGLConfig config)
31 {
32     EGLint red, green, blue, alpha;
33     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
34     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
35     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
36     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
37     return ((red == 16) && (green == 16) && (blue == 16) && (alpha == 16));
38 }
39 
IsRGB10_A2Config(EGLDisplay display,EGLConfig config)40 bool IsRGB10_A2Config(EGLDisplay display, EGLConfig config)
41 {
42     EGLint red, green, blue, alpha;
43     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
44     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
45     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
46     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
47     return ((red == 10) && (green == 10) && (blue == 10) && (alpha == 2));
48 }
49 
50 // Queries EGL config to determine if multisampled or not
IsMultisampledConfig(EGLDisplay display,EGLConfig config)51 bool IsMultisampledConfig(EGLDisplay display, EGLConfig config)
52 {
53     EGLint samples = 0;
54     eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
55     return (samples > 1);
56 }
57 
ShouldSkipConfig(EGLDisplay display,EGLConfig config,bool windowSurfaceTest)58 bool ShouldSkipConfig(EGLDisplay display, EGLConfig config, bool windowSurfaceTest)
59 {
60     // Skip multisampled configurations due to test instability.
61     if (IsMultisampledConfig(display, config))
62         return true;
63 
64     // Disable RGBA16F/RGB10_A2 on Android due to OSWindow on Android not providing compatible
65     // windows (http://anglebug.com/3156)
66     if (IsAndroid())
67     {
68         if (IsRGB10_A2Config(display, config))
69             return true;
70 
71         if (IsRGBA16FConfig(display, config))
72             return windowSurfaceTest;
73     }
74 
75     return false;
76 }
77 
GetConfigs(EGLDisplay display)78 std::vector<EGLConfig> GetConfigs(EGLDisplay display)
79 {
80     int nConfigs = 0;
81     if (eglGetConfigs(display, nullptr, 0, &nConfigs) != EGL_TRUE)
82     {
83         std::cerr << "EGLContextCompatibilityTest: eglGetConfigs error\n";
84         return {};
85     }
86     if (nConfigs == 0)
87     {
88         std::cerr << "EGLContextCompatibilityTest: no configs\n";
89         return {};
90     }
91 
92     std::vector<EGLConfig> configs;
93 
94     int nReturnedConfigs = 0;
95     configs.resize(nConfigs);
96     if (eglGetConfigs(display, configs.data(), nConfigs, &nReturnedConfigs) != EGL_TRUE)
97     {
98         std::cerr << "EGLContextCompatibilityTest: eglGetConfigs error\n";
99         return {};
100     }
101     if (nConfigs != nReturnedConfigs)
102     {
103         std::cerr << "EGLContextCompatibilityTest: eglGetConfigs returned wrong count\n";
104         return {};
105     }
106 
107     return configs;
108 }
109 
FromRenderer(EGLint renderer)110 PlatformParameters FromRenderer(EGLint renderer)
111 {
112     return WithNoFixture(
113         PlatformParameters(EGL_OPENGL_ES_API, 2, 0, 0, EGLPlatformParameters(renderer)));
114 }
115 
EGLConfigName(EGLDisplay display,EGLConfig config)116 std::string EGLConfigName(EGLDisplay display, EGLConfig config)
117 {
118     EGLint red;
119     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
120     EGLint green;
121     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
122     EGLint blue;
123     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
124     EGLint alpha;
125     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
126     EGLint depth;
127     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth);
128     EGLint stencil;
129     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil);
130     EGLint samples;
131     eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
132 
133     std::stringstream strstr;
134     if (red > 0)
135     {
136         strstr << "R" << red;
137     }
138     if (green > 0)
139     {
140         strstr << "G" << green;
141     }
142     if (blue > 0)
143     {
144         strstr << "B" << blue;
145     }
146     if (alpha > 0)
147     {
148         strstr << "A" << alpha;
149     }
150     if (depth > 0)
151     {
152         strstr << "D" << depth;
153     }
154     if (stencil > 0)
155     {
156         strstr << "S" << stencil;
157     }
158     if (samples > 0)
159     {
160         strstr << "MS" << samples;
161     }
162     return strstr.str();
163 }
164 
165 const std::array<EGLint, 3> kContextAttribs = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
166 
167 class EGLContextCompatibilityTest : public ANGLETestBase, public testing::Test
168 {
169   public:
EGLContextCompatibilityTest(EGLint renderer)170     EGLContextCompatibilityTest(EGLint renderer)
171         : ANGLETestBase(FromRenderer(renderer)), mRenderer(renderer)
172     {}
173 
SetUp()174     void SetUp() final
175     {
176         ANGLETestBase::ANGLETestSetUp();
177         ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);
178 
179         EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, mRenderer, EGL_NONE};
180         mDisplay           = eglGetPlatformDisplayEXT(
181             EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
182         ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
183 
184         ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);
185 
186         int nConfigs = 0;
187         ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE);
188         ASSERT_TRUE(nConfigs != 0);
189 
190         int nReturnedConfigs = 0;
191         mConfigs.resize(nConfigs);
192         ASSERT_TRUE(eglGetConfigs(mDisplay, mConfigs.data(), nConfigs, &nReturnedConfigs) ==
193                     EGL_TRUE);
194         ASSERT_TRUE(nConfigs == nReturnedConfigs);
195     }
196 
TearDown()197     void TearDown() final
198     {
199         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
200         eglTerminate(mDisplay);
201         ANGLETestBase::ANGLETestTearDown();
202     }
203 
204   protected:
areConfigsCompatible(EGLConfig c1,EGLConfig c2,EGLint surfaceBit)205     bool areConfigsCompatible(EGLConfig c1, EGLConfig c2, EGLint surfaceBit)
206     {
207         EGLint colorBufferType1, colorBufferType2;
208         EGLint red1, red2, green1, green2, blue1, blue2, alpha1, alpha2;
209         EGLint depth1, depth2, stencil1, stencil2;
210         EGLint surfaceType1, surfaceType2;
211 
212         eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_BUFFER_TYPE, &colorBufferType1);
213         eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_BUFFER_TYPE, &colorBufferType2);
214 
215         eglGetConfigAttrib(mDisplay, c1, EGL_RED_SIZE, &red1);
216         eglGetConfigAttrib(mDisplay, c2, EGL_RED_SIZE, &red2);
217         eglGetConfigAttrib(mDisplay, c1, EGL_GREEN_SIZE, &green1);
218         eglGetConfigAttrib(mDisplay, c2, EGL_GREEN_SIZE, &green2);
219         eglGetConfigAttrib(mDisplay, c1, EGL_BLUE_SIZE, &blue1);
220         eglGetConfigAttrib(mDisplay, c2, EGL_BLUE_SIZE, &blue2);
221         eglGetConfigAttrib(mDisplay, c1, EGL_ALPHA_SIZE, &alpha1);
222         eglGetConfigAttrib(mDisplay, c2, EGL_ALPHA_SIZE, &alpha2);
223 
224         eglGetConfigAttrib(mDisplay, c1, EGL_DEPTH_SIZE, &depth1);
225         eglGetConfigAttrib(mDisplay, c2, EGL_DEPTH_SIZE, &depth2);
226         eglGetConfigAttrib(mDisplay, c1, EGL_STENCIL_SIZE, &stencil1);
227         eglGetConfigAttrib(mDisplay, c2, EGL_STENCIL_SIZE, &stencil2);
228 
229         eglGetConfigAttrib(mDisplay, c1, EGL_SURFACE_TYPE, &surfaceType1);
230         eglGetConfigAttrib(mDisplay, c2, EGL_SURFACE_TYPE, &surfaceType2);
231 
232         EGLint colorComponentType1 = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
233         EGLint colorComponentType2 = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
234         if (IsEGLDisplayExtensionEnabled(mDisplay, "EGL_EXT_pixel_format_float"))
235         {
236             eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_COMPONENT_TYPE_EXT, &colorComponentType1);
237             eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_COMPONENT_TYPE_EXT, &colorComponentType2);
238         }
239 
240         EXPECT_EGL_SUCCESS();
241 
242         return colorBufferType1 == colorBufferType2 && red1 == red2 && green1 == green2 &&
243                blue1 == blue2 && alpha1 == alpha2 && colorComponentType1 == colorComponentType2 &&
244                depth1 == depth2 && stencil1 == stencil2 && (surfaceType1 & surfaceBit) != 0 &&
245                (surfaceType2 & surfaceBit) != 0;
246     }
247 
testWindowCompatibility(EGLConfig windowConfig,EGLConfig contextConfig,bool compatible) const248     void testWindowCompatibility(EGLConfig windowConfig,
249                                  EGLConfig contextConfig,
250                                  bool compatible) const
251     {
252         OSWindow *osWindow = OSWindow::New();
253         ASSERT_TRUE(osWindow != nullptr);
254         osWindow->initialize("EGLContextCompatibilityTest", 500, 500);
255 
256         EGLContext context =
257             eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, kContextAttribs.data());
258         ASSERT_TRUE(context != EGL_NO_CONTEXT);
259 
260         EGLSurface window =
261             eglCreateWindowSurface(mDisplay, windowConfig, osWindow->getNativeWindow(), nullptr);
262         ASSERT_EGL_SUCCESS();
263 
264         if (compatible)
265         {
266             testClearSurface(window, windowConfig, context);
267         }
268         else
269         {
270             testMakeCurrentFails(window, context);
271         }
272 
273         eglDestroySurface(mDisplay, window);
274         ASSERT_EGL_SUCCESS();
275 
276         eglDestroyContext(mDisplay, context);
277         ASSERT_EGL_SUCCESS();
278 
279         OSWindow::Delete(&osWindow);
280     }
281 
testPbufferCompatibility(EGLConfig pbufferConfig,EGLConfig contextConfig,bool compatible) const282     void testPbufferCompatibility(EGLConfig pbufferConfig,
283                                   EGLConfig contextConfig,
284                                   bool compatible) const
285     {
286         EGLContext context =
287             eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, kContextAttribs.data());
288         ASSERT_TRUE(context != EGL_NO_CONTEXT);
289 
290         const EGLint pBufferAttribs[] = {
291             EGL_WIDTH, 500, EGL_HEIGHT, 500, EGL_NONE,
292         };
293         EGLSurface pbuffer = eglCreatePbufferSurface(mDisplay, pbufferConfig, pBufferAttribs);
294         ASSERT_TRUE(pbuffer != EGL_NO_SURFACE);
295 
296         if (compatible)
297         {
298             testClearSurface(pbuffer, pbufferConfig, context);
299         }
300         else
301         {
302             testMakeCurrentFails(pbuffer, context);
303         }
304 
305         eglDestroySurface(mDisplay, pbuffer);
306         ASSERT_EGL_SUCCESS();
307 
308         eglDestroyContext(mDisplay, context);
309         ASSERT_EGL_SUCCESS();
310     }
311 
312     std::vector<EGLConfig> mConfigs;
313     EGLDisplay mDisplay = EGL_NO_DISPLAY;
314     EGLint mRenderer    = 0;
315 
316   private:
testClearSurface(EGLSurface surface,EGLConfig surfaceConfig,EGLContext context) const317     void testClearSurface(EGLSurface surface, EGLConfig surfaceConfig, EGLContext context) const
318     {
319         eglMakeCurrent(mDisplay, surface, surface, context);
320         ASSERT_EGL_SUCCESS();
321 
322         glViewport(0, 0, 500, 500);
323         glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
324         glClear(GL_COLOR_BUFFER_BIT);
325         ASSERT_GL_NO_ERROR();
326 
327         EGLint surfaceCompontentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
328         if (IsEGLDisplayExtensionEnabled(mDisplay, "EGL_EXT_pixel_format_float"))
329         {
330             eglGetConfigAttrib(mDisplay, surfaceConfig, EGL_COLOR_COMPONENT_TYPE_EXT,
331                                &surfaceCompontentType);
332         }
333 
334         if (surfaceCompontentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
335         {
336             EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255);
337         }
338         else
339         {
340             EXPECT_PIXEL_32F_EQ(250, 250, 0, 0, 1.0f, 1.0f);
341         }
342 
343         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
344         ASSERT_EGL_SUCCESS();
345     }
346 
testMakeCurrentFails(EGLSurface surface,EGLContext context) const347     void testMakeCurrentFails(EGLSurface surface, EGLContext context) const
348     {
349         eglMakeCurrent(mDisplay, surface, surface, context);
350         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
351     }
352 };
353 
354 // The test is split in several subtest so that simple cases
355 // are tested separately. Also each surface types are not tested
356 // together.
357 
358 // Basic test checking contexts and windows created with the
359 // same config can render.
360 class EGLContextCompatibilityTest_WindowSameConfig : public EGLContextCompatibilityTest
361 {
362   public:
EGLContextCompatibilityTest_WindowSameConfig(EGLint renderer,size_t configIndex)363     EGLContextCompatibilityTest_WindowSameConfig(EGLint renderer, size_t configIndex)
364         : EGLContextCompatibilityTest(renderer), mConfigIndex(configIndex)
365     {}
366 
TestBody()367     void TestBody() override
368     {
369         EGLConfig config = mConfigs[mConfigIndex];
370 
371         EGLint surfaceType;
372         eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
373         ASSERT_EGL_SUCCESS();
374 
375         ANGLE_SKIP_TEST_IF((surfaceType & EGL_WINDOW_BIT) == 0);
376 
377         testWindowCompatibility(config, config, true);
378     }
379 
380     EGLint mConfigIndex;
381 };
382 
383 // Basic test checking contexts and pbuffers created with the
384 // same config can render.
385 class EGLContextCompatibilityTest_PbufferSameConfig : public EGLContextCompatibilityTest
386 {
387   public:
EGLContextCompatibilityTest_PbufferSameConfig(EGLint renderer,size_t configIndex)388     EGLContextCompatibilityTest_PbufferSameConfig(EGLint renderer, size_t configIndex)
389         : EGLContextCompatibilityTest(renderer), mConfigIndex(configIndex)
390     {}
391 
TestBody()392     void TestBody() override
393     {
394         EGLConfig config = mConfigs[mConfigIndex];
395 
396         EGLint surfaceType;
397         eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
398         ASSERT_EGL_SUCCESS();
399 
400         ANGLE_SKIP_TEST_IF((surfaceType & EGL_PBUFFER_BIT) == 0);
401 
402         testPbufferCompatibility(config, config, true);
403     }
404 
405     EGLint mConfigIndex;
406 };
407 
408 // Check that a context rendering to a window with a different
409 // config works or errors according to the EGL compatibility rules
410 class EGLContextCompatibilityTest_WindowDifferentConfig : public EGLContextCompatibilityTest
411 {
412   public:
EGLContextCompatibilityTest_WindowDifferentConfig(EGLint renderer,size_t configIndexA,size_t configIndexB)413     EGLContextCompatibilityTest_WindowDifferentConfig(EGLint renderer,
414                                                       size_t configIndexA,
415                                                       size_t configIndexB)
416         : EGLContextCompatibilityTest(renderer),
417           mConfigIndexA(configIndexA),
418           mConfigIndexB(configIndexB)
419     {}
420 
TestBody()421     void TestBody() override
422     {
423         EGLConfig config1 = mConfigs[mConfigIndexA];
424         EGLConfig config2 = mConfigs[mConfigIndexB];
425 
426         EGLint surfaceType;
427         eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
428         ASSERT_EGL_SUCCESS();
429 
430         ANGLE_SKIP_TEST_IF((surfaceType & EGL_WINDOW_BIT) == 0);
431 
432         testWindowCompatibility(config1, config2,
433                                 areConfigsCompatible(config1, config2, EGL_WINDOW_BIT));
434     }
435 
436     EGLint mConfigIndexA;
437     EGLint mConfigIndexB;
438 };
439 
440 // Check that a context rendering to a pbuffer with a different
441 // config works or errors according to the EGL compatibility rules
442 class EGLContextCompatibilityTest_PbufferDifferentConfig : public EGLContextCompatibilityTest
443 {
444   public:
EGLContextCompatibilityTest_PbufferDifferentConfig(EGLint renderer,size_t configIndexA,size_t configIndexB)445     EGLContextCompatibilityTest_PbufferDifferentConfig(EGLint renderer,
446                                                        size_t configIndexA,
447                                                        size_t configIndexB)
448         : EGLContextCompatibilityTest(renderer),
449           mConfigIndexA(configIndexA),
450           mConfigIndexB(configIndexB)
451     {}
452 
TestBody()453     void TestBody() override
454     {
455         EGLConfig config1 = mConfigs[mConfigIndexA];
456         EGLConfig config2 = mConfigs[mConfigIndexB];
457 
458         EGLint surfaceType;
459         eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
460         ASSERT_EGL_SUCCESS();
461 
462         ANGLE_SKIP_TEST_IF((surfaceType & EGL_PBUFFER_BIT) == 0);
463 
464         testPbufferCompatibility(config1, config2,
465                                  areConfigsCompatible(config1, config2, EGL_PBUFFER_BIT));
466     }
467 
468     EGLint mConfigIndexA;
469     EGLint mConfigIndexB;
470 };
471 }  // namespace
472 
RegisterContextCompatibilityTests()473 void RegisterContextCompatibilityTests()
474 {
475     // Linux failures: http://anglebug.com/4990
476     // Also wrong drivers loaded under xvfb due to egl* calls: https://anglebug.com/8083
477     if (IsLinux())
478     {
479         std::cerr << "EGLContextCompatibilityTest: skipped on Linux\n";
480         return;
481     }
482 
483     std::vector<EGLint> renderers = {{
484         EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
485         EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
486         EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
487         EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
488         EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE,
489     }};
490 
491     LoadEntryPointsWithUtilLoader(angle::GLESDriverType::AngleEGL);
492 
493     if (eglGetPlatformDisplayEXT == nullptr)
494     {
495         std::cerr << "EGLContextCompatibilityTest: missing eglGetPlatformDisplayEXT\n";
496         return;
497     }
498 
499     for (EGLint renderer : renderers)
500     {
501         PlatformParameters params = FromRenderer(renderer);
502         if (!IsPlatformAvailable(params))
503             continue;
504 
505         EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, renderer, EGL_NONE};
506         EGLDisplay display = eglGetPlatformDisplayEXT(
507             EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
508         if (display == EGL_NO_DISPLAY)
509         {
510             std::cerr << "EGLContextCompatibilityTest: eglGetPlatformDisplayEXT error\n";
511             return;
512         }
513 
514         if (eglInitialize(display, nullptr, nullptr) != EGL_TRUE)
515         {
516             std::cerr << "EGLContextCompatibilityTest: eglInitialize error\n";
517             return;
518         }
519 
520         std::vector<EGLConfig> configs;
521         std::vector<std::string> configNames;
522         std::string rendererName = GetRendererName(renderer);
523 
524         {
525             std::unordered_set<std::string> configNameSet;
526 
527             for (EGLConfig config : GetConfigs(display))
528             {
529                 std::string configName = EGLConfigName(display, config);
530                 // Skip configs with duplicate names
531                 if (configNameSet.count(configName) == 0)
532                 {
533                     configNames.push_back(configName);
534                     configNameSet.insert(configName);
535                     configs.push_back(config);
536                 }
537             }
538         }
539 
540         for (size_t configIndex = 0; configIndex < configs.size(); ++configIndex)
541         {
542             if (ShouldSkipConfig(display, configs[configIndex], true))
543                 continue;
544 
545             std::stringstream nameStr;
546             nameStr << "WindowSameConfig/" << rendererName << "_" << configNames[configIndex];
547             std::string name = nameStr.str();
548 
549             testing::RegisterTest(
550                 "EGLContextCompatibilityTest", name.c_str(), nullptr, nullptr, __FILE__, __LINE__,
551                 [renderer, configIndex]() -> EGLContextCompatibilityTest * {
552                     return new EGLContextCompatibilityTest_WindowSameConfig(renderer, configIndex);
553                 });
554         }
555 
556         for (size_t configIndex = 0; configIndex < configs.size(); ++configIndex)
557         {
558             if (ShouldSkipConfig(display, configs[configIndex], false))
559                 continue;
560 
561             std::stringstream nameStr;
562             nameStr << "PbufferSameConfig/" << rendererName << "_" << configNames[configIndex];
563             std::string name = nameStr.str();
564 
565             testing::RegisterTest(
566                 "EGLContextCompatibilityTest", name.c_str(), nullptr, nullptr, __FILE__, __LINE__,
567                 [renderer, configIndex]() -> EGLContextCompatibilityTest * {
568                     return new EGLContextCompatibilityTest_PbufferSameConfig(renderer, configIndex);
569                 });
570         }
571 
572         // Because there are so many permutations, we skip some configs randomly.
573         // Attempt to run at most 100 tests per renderer.
574         RNG rng(0);
575         constexpr uint32_t kMaximumTestsPerRenderer = 100;
576         const uint32_t kTestCount = static_cast<uint32_t>(configs.size() * configs.size());
577         const float kSkipP =
578             1.0f - (static_cast<float>(std::min(kMaximumTestsPerRenderer, kTestCount)) /
579                     static_cast<float>(kTestCount));
580 
581         for (size_t configIndexA = 0; configIndexA < configs.size(); ++configIndexA)
582         {
583             if (ShouldSkipConfig(display, configs[configIndexA], true))
584                 continue;
585 
586             std::string configNameA = configNames[configIndexA];
587 
588             for (size_t configIndexB = 0; configIndexB < configs.size(); ++configIndexB)
589             {
590                 if (ShouldSkipConfig(display, configs[configIndexB], true))
591                     continue;
592 
593                 if (rng.randomFloat() < kSkipP)
594                     continue;
595 
596                 std::string configNameB = configNames[configIndexB];
597 
598                 std::stringstream nameStr;
599                 nameStr << "WindowDifferentConfig/" << rendererName << "_" << configNameA << "_"
600                         << configNameB;
601                 std::string name = nameStr.str();
602 
603                 testing::RegisterTest(
604                     "EGLContextCompatibilityTest", name.c_str(), nullptr, nullptr, __FILE__,
605                     __LINE__,
606                     [renderer, configIndexA, configIndexB]() -> EGLContextCompatibilityTest * {
607                         return new EGLContextCompatibilityTest_WindowDifferentConfig(
608                             renderer, configIndexA, configIndexB);
609                     });
610             }
611         }
612 
613         for (size_t configIndexA = 0; configIndexA < configs.size(); ++configIndexA)
614         {
615             if (ShouldSkipConfig(display, configs[configIndexA], false))
616                 continue;
617 
618             std::string configNameA = configNames[configIndexA];
619 
620             for (size_t configIndexB = 0; configIndexB < configs.size(); ++configIndexB)
621             {
622                 if (ShouldSkipConfig(display, configs[configIndexB], false))
623                     continue;
624 
625                 if (rng.randomFloat() < kSkipP)
626                     continue;
627 
628                 std::string configNameB = configNames[configIndexB];
629 
630                 std::stringstream nameStr;
631                 nameStr << "PbufferDifferentConfig/" << rendererName << "_" << configNameA << "_"
632                         << configNameB;
633                 std::string name = nameStr.str();
634 
635                 testing::RegisterTest(
636                     "EGLContextCompatibilityTest", name.c_str(), nullptr, nullptr, __FILE__,
637                     __LINE__,
638                     [renderer, configIndexA, configIndexB]() -> EGLContextCompatibilityTest * {
639                         return new EGLContextCompatibilityTest_PbufferDifferentConfig(
640                             renderer, configIndexA, configIndexB);
641                     });
642             }
643         }
644 
645         if (eglTerminate(display) == EGL_FALSE)
646         {
647             std::cerr << "EGLContextCompatibilityTest: eglTerminate error\n";
648             return;
649         }
650     }
651 }
652