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