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