xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLContextCompatibilityTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/42261830)
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(PlatformParameters(2, 0, EGLPlatformParameters(renderer)));
113 }
114 
EGLConfigName(EGLDisplay display,EGLConfig config)115 std::string EGLConfigName(EGLDisplay display, EGLConfig config)
116 {
117     EGLint red;
118     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
119     EGLint green;
120     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
121     EGLint blue;
122     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
123     EGLint alpha;
124     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
125     EGLint depth;
126     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth);
127     EGLint stencil;
128     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil);
129     EGLint samples;
130     eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
131 
132     std::stringstream strstr;
133     if (red > 0)
134     {
135         strstr << "R" << red;
136     }
137     if (green > 0)
138     {
139         strstr << "G" << green;
140     }
141     if (blue > 0)
142     {
143         strstr << "B" << blue;
144     }
145     if (alpha > 0)
146     {
147         strstr << "A" << alpha;
148     }
149     if (depth > 0)
150     {
151         strstr << "D" << depth;
152     }
153     if (stencil > 0)
154     {
155         strstr << "S" << stencil;
156     }
157     if (samples > 0)
158     {
159         strstr << "MS" << samples;
160     }
161     return strstr.str();
162 }
163 
164 const std::array<EGLint, 3> kContextAttribs = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
165 
166 class EGLContextCompatibilityTest : public ANGLETestBase, public testing::Test
167 {
168   public:
EGLContextCompatibilityTest(EGLint renderer)169     EGLContextCompatibilityTest(EGLint renderer)
170         : ANGLETestBase(FromRenderer(renderer)), mRenderer(renderer)
171     {}
172 
SetUp()173     void SetUp() final
174     {
175         ANGLETestBase::ANGLETestSetUp();
176         ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);
177 
178         EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, mRenderer, EGL_NONE};
179         mDisplay           = eglGetPlatformDisplayEXT(
180             EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
181         ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
182 
183         ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);
184 
185         int nConfigs = 0;
186         ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE);
187         ASSERT_TRUE(nConfigs != 0);
188 
189         int nReturnedConfigs = 0;
190         mConfigs.resize(nConfigs);
191         ASSERT_TRUE(eglGetConfigs(mDisplay, mConfigs.data(), nConfigs, &nReturnedConfigs) ==
192                     EGL_TRUE);
193         ASSERT_TRUE(nConfigs == nReturnedConfigs);
194     }
195 
TearDown()196     void TearDown() final
197     {
198         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
199         eglTerminate(mDisplay);
200         ANGLETestBase::ANGLETestTearDown();
201     }
202 
203   protected:
areConfigsCompatible(EGLConfig c1,EGLConfig c2,EGLint surfaceBit)204     bool areConfigsCompatible(EGLConfig c1, EGLConfig c2, EGLint surfaceBit)
205     {
206         EGLint colorBufferType1, colorBufferType2;
207         EGLint red1, red2, green1, green2, blue1, blue2, alpha1, alpha2;
208         EGLint depth1, depth2, stencil1, stencil2;
209         EGLint surfaceType1, surfaceType2;
210 
211         eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_BUFFER_TYPE, &colorBufferType1);
212         eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_BUFFER_TYPE, &colorBufferType2);
213 
214         eglGetConfigAttrib(mDisplay, c1, EGL_RED_SIZE, &red1);
215         eglGetConfigAttrib(mDisplay, c2, EGL_RED_SIZE, &red2);
216         eglGetConfigAttrib(mDisplay, c1, EGL_GREEN_SIZE, &green1);
217         eglGetConfigAttrib(mDisplay, c2, EGL_GREEN_SIZE, &green2);
218         eglGetConfigAttrib(mDisplay, c1, EGL_BLUE_SIZE, &blue1);
219         eglGetConfigAttrib(mDisplay, c2, EGL_BLUE_SIZE, &blue2);
220         eglGetConfigAttrib(mDisplay, c1, EGL_ALPHA_SIZE, &alpha1);
221         eglGetConfigAttrib(mDisplay, c2, EGL_ALPHA_SIZE, &alpha2);
222 
223         eglGetConfigAttrib(mDisplay, c1, EGL_DEPTH_SIZE, &depth1);
224         eglGetConfigAttrib(mDisplay, c2, EGL_DEPTH_SIZE, &depth2);
225         eglGetConfigAttrib(mDisplay, c1, EGL_STENCIL_SIZE, &stencil1);
226         eglGetConfigAttrib(mDisplay, c2, EGL_STENCIL_SIZE, &stencil2);
227 
228         eglGetConfigAttrib(mDisplay, c1, EGL_SURFACE_TYPE, &surfaceType1);
229         eglGetConfigAttrib(mDisplay, c2, EGL_SURFACE_TYPE, &surfaceType2);
230 
231         EGLint colorComponentType1 = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
232         EGLint colorComponentType2 = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
233         if (IsEGLDisplayExtensionEnabled(mDisplay, "EGL_EXT_pixel_format_float"))
234         {
235             eglGetConfigAttrib(mDisplay, c1, EGL_COLOR_COMPONENT_TYPE_EXT, &colorComponentType1);
236             eglGetConfigAttrib(mDisplay, c2, EGL_COLOR_COMPONENT_TYPE_EXT, &colorComponentType2);
237         }
238 
239         EXPECT_EGL_SUCCESS();
240 
241         return colorBufferType1 == colorBufferType2 && red1 == red2 && green1 == green2 &&
242                blue1 == blue2 && alpha1 == alpha2 && colorComponentType1 == colorComponentType2 &&
243                depth1 == depth2 && stencil1 == stencil2 && (surfaceType1 & surfaceBit) != 0 &&
244                (surfaceType2 & surfaceBit) != 0;
245     }
246 
testWindowCompatibility(EGLConfig windowConfig,EGLConfig contextConfig,bool compatible) const247     void testWindowCompatibility(EGLConfig windowConfig,
248                                  EGLConfig contextConfig,
249                                  bool compatible) const
250     {
251         OSWindow *osWindow = OSWindow::New();
252         ASSERT_TRUE(osWindow != nullptr);
253         osWindow->initialize("EGLContextCompatibilityTest", 500, 500);
254 
255         EGLContext context =
256             eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, kContextAttribs.data());
257         ASSERT_TRUE(context != EGL_NO_CONTEXT);
258 
259         EGLSurface window =
260             eglCreateWindowSurface(mDisplay, windowConfig, osWindow->getNativeWindow(), nullptr);
261         ASSERT_EGL_SUCCESS();
262 
263         if (compatible)
264         {
265             testClearSurface(window, windowConfig, context);
266         }
267         else
268         {
269             testMakeCurrentFails(window, context);
270         }
271 
272         eglDestroySurface(mDisplay, window);
273         ASSERT_EGL_SUCCESS();
274 
275         eglDestroyContext(mDisplay, context);
276         ASSERT_EGL_SUCCESS();
277 
278         OSWindow::Delete(&osWindow);
279     }
280 
testPbufferCompatibility(EGLConfig pbufferConfig,EGLConfig contextConfig,bool compatible) const281     void testPbufferCompatibility(EGLConfig pbufferConfig,
282                                   EGLConfig contextConfig,
283                                   bool compatible) const
284     {
285         EGLContext context =
286             eglCreateContext(mDisplay, contextConfig, EGL_NO_CONTEXT, kContextAttribs.data());
287         ASSERT_TRUE(context != EGL_NO_CONTEXT);
288 
289         const EGLint pBufferAttribs[] = {
290             EGL_WIDTH, 500, EGL_HEIGHT, 500, EGL_NONE,
291         };
292         EGLSurface pbuffer = eglCreatePbufferSurface(mDisplay, pbufferConfig, pBufferAttribs);
293         ASSERT_TRUE(pbuffer != EGL_NO_SURFACE);
294 
295         if (compatible)
296         {
297             testClearSurface(pbuffer, pbufferConfig, context);
298         }
299         else
300         {
301             testMakeCurrentFails(pbuffer, context);
302         }
303 
304         eglDestroySurface(mDisplay, pbuffer);
305         ASSERT_EGL_SUCCESS();
306 
307         eglDestroyContext(mDisplay, context);
308         ASSERT_EGL_SUCCESS();
309     }
310 
311     std::vector<EGLConfig> mConfigs;
312     EGLDisplay mDisplay = EGL_NO_DISPLAY;
313     EGLint mRenderer    = 0;
314 
315   private:
testClearSurface(EGLSurface surface,EGLConfig surfaceConfig,EGLContext context) const316     void testClearSurface(EGLSurface surface, EGLConfig surfaceConfig, EGLContext context) const
317     {
318         eglMakeCurrent(mDisplay, surface, surface, context);
319         ASSERT_EGL_SUCCESS();
320 
321         glViewport(0, 0, 500, 500);
322         glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
323         glClear(GL_COLOR_BUFFER_BIT);
324         ASSERT_GL_NO_ERROR();
325 
326         EGLint surfaceCompontentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
327         if (IsEGLDisplayExtensionEnabled(mDisplay, "EGL_EXT_pixel_format_float"))
328         {
329             eglGetConfigAttrib(mDisplay, surfaceConfig, EGL_COLOR_COMPONENT_TYPE_EXT,
330                                &surfaceCompontentType);
331         }
332 
333         if (surfaceCompontentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT)
334         {
335             EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255);
336         }
337         else
338         {
339             EXPECT_PIXEL_32F_EQ(250, 250, 0, 0, 1.0f, 1.0f);
340         }
341 
342         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
343         ASSERT_EGL_SUCCESS();
344     }
345 
testMakeCurrentFails(EGLSurface surface,EGLContext context) const346     void testMakeCurrentFails(EGLSurface surface, EGLContext context) const
347     {
348         eglMakeCurrent(mDisplay, surface, surface, context);
349         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
350     }
351 };
352 
353 // The test is split in several subtest so that simple cases
354 // are tested separately. Also each surface types are not tested
355 // together.
356 
357 // Basic test checking contexts and windows created with the
358 // same config can render.
359 class EGLContextCompatibilityTest_WindowSameConfig : public EGLContextCompatibilityTest
360 {
361   public:
EGLContextCompatibilityTest_WindowSameConfig(EGLint renderer,size_t configIndex)362     EGLContextCompatibilityTest_WindowSameConfig(EGLint renderer, size_t configIndex)
363         : EGLContextCompatibilityTest(renderer), mConfigIndex(configIndex)
364     {}
365 
TestBody()366     void TestBody() override
367     {
368         EGLConfig config = mConfigs[mConfigIndex];
369 
370         EGLint surfaceType;
371         eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
372         ASSERT_EGL_SUCCESS();
373 
374         ANGLE_SKIP_TEST_IF((surfaceType & EGL_WINDOW_BIT) == 0);
375 
376         testWindowCompatibility(config, config, true);
377     }
378 
379     EGLint mConfigIndex;
380 };
381 
382 // Basic test checking contexts and pbuffers created with the
383 // same config can render.
384 class EGLContextCompatibilityTest_PbufferSameConfig : public EGLContextCompatibilityTest
385 {
386   public:
EGLContextCompatibilityTest_PbufferSameConfig(EGLint renderer,size_t configIndex)387     EGLContextCompatibilityTest_PbufferSameConfig(EGLint renderer, size_t configIndex)
388         : EGLContextCompatibilityTest(renderer), mConfigIndex(configIndex)
389     {}
390 
TestBody()391     void TestBody() override
392     {
393         EGLConfig config = mConfigs[mConfigIndex];
394 
395         EGLint surfaceType;
396         eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
397         ASSERT_EGL_SUCCESS();
398 
399         ANGLE_SKIP_TEST_IF((surfaceType & EGL_PBUFFER_BIT) == 0);
400 
401         testPbufferCompatibility(config, config, true);
402     }
403 
404     EGLint mConfigIndex;
405 };
406 
407 // Check that a context rendering to a window with a different
408 // config works or errors according to the EGL compatibility rules
409 class EGLContextCompatibilityTest_WindowDifferentConfig : public EGLContextCompatibilityTest
410 {
411   public:
EGLContextCompatibilityTest_WindowDifferentConfig(EGLint renderer,size_t configIndexA,size_t configIndexB)412     EGLContextCompatibilityTest_WindowDifferentConfig(EGLint renderer,
413                                                       size_t configIndexA,
414                                                       size_t configIndexB)
415         : EGLContextCompatibilityTest(renderer),
416           mConfigIndexA(configIndexA),
417           mConfigIndexB(configIndexB)
418     {}
419 
TestBody()420     void TestBody() override
421     {
422         EGLConfig config1 = mConfigs[mConfigIndexA];
423         EGLConfig config2 = mConfigs[mConfigIndexB];
424 
425         EGLint surfaceType;
426         eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
427         ASSERT_EGL_SUCCESS();
428 
429         ANGLE_SKIP_TEST_IF((surfaceType & EGL_WINDOW_BIT) == 0);
430 
431         testWindowCompatibility(config1, config2,
432                                 areConfigsCompatible(config1, config2, EGL_WINDOW_BIT));
433     }
434 
435     EGLint mConfigIndexA;
436     EGLint mConfigIndexB;
437 };
438 
439 // Check that a context rendering to a pbuffer with a different
440 // config works or errors according to the EGL compatibility rules
441 class EGLContextCompatibilityTest_PbufferDifferentConfig : public EGLContextCompatibilityTest
442 {
443   public:
EGLContextCompatibilityTest_PbufferDifferentConfig(EGLint renderer,size_t configIndexA,size_t configIndexB)444     EGLContextCompatibilityTest_PbufferDifferentConfig(EGLint renderer,
445                                                        size_t configIndexA,
446                                                        size_t configIndexB)
447         : EGLContextCompatibilityTest(renderer),
448           mConfigIndexA(configIndexA),
449           mConfigIndexB(configIndexB)
450     {}
451 
TestBody()452     void TestBody() override
453     {
454         EGLConfig config1 = mConfigs[mConfigIndexA];
455         EGLConfig config2 = mConfigs[mConfigIndexB];
456 
457         EGLint surfaceType;
458         eglGetConfigAttrib(mDisplay, config1, EGL_SURFACE_TYPE, &surfaceType);
459         ASSERT_EGL_SUCCESS();
460 
461         ANGLE_SKIP_TEST_IF((surfaceType & EGL_PBUFFER_BIT) == 0);
462 
463         testPbufferCompatibility(config1, config2,
464                                  areConfigsCompatible(config1, config2, EGL_PBUFFER_BIT));
465     }
466 
467     EGLint mConfigIndexA;
468     EGLint mConfigIndexB;
469 };
470 }  // namespace
471 
RegisterContextCompatibilityTests()472 void RegisterContextCompatibilityTests()
473 {
474     // Linux failures: http://anglebug.com/42263563
475     // Also wrong drivers loaded under xvfb due to egl* calls: https://anglebug.com/42266535
476     if (IsLinux())
477     {
478         std::cerr << "EGLContextCompatibilityTest: skipped on Linux\n";
479         return;
480     }
481 
482     std::vector<EGLint> renderers = {{
483         EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
484         EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
485         EGL_PLATFORM_ANGLE_TYPE_METAL_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