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 // EGLSurfaceTest:
7 // Tests pertaining to egl::Surface.
8 //
9
10 #include <gtest/gtest.h>
11
12 #include <vector>
13
14 #include "common/platform.h"
15 #include "test_utils/ANGLETest.h"
16 #include "util/EGLWindow.h"
17 #include "util/OSWindow.h"
18 #include "util/Timer.h"
19
20 #if defined(ANGLE_ENABLE_D3D11)
21 # define INITGUID
22 # include <guiddef.h>
23
24 # include <d3d11.h>
25 # include <dcomp.h>
26 #endif
27
28 using namespace angle;
29
30 namespace
31 {
32
33 class EGLSurfaceTest : public ANGLETest
34 {
35 protected:
EGLSurfaceTest()36 EGLSurfaceTest()
37 : mDisplay(EGL_NO_DISPLAY),
38 mWindowSurface(EGL_NO_SURFACE),
39 mPbufferSurface(EGL_NO_SURFACE),
40 mContext(EGL_NO_CONTEXT),
41 mSecondContext(EGL_NO_CONTEXT),
42 mOSWindow(nullptr)
43 {}
44
testSetUp()45 void testSetUp() override
46 {
47 mOSWindow = OSWindow::New();
48 mOSWindow->initialize("EGLSurfaceTest", 64, 64);
49 }
50
51 // Release any resources created in the test body
testTearDown()52 void testTearDown() override
53 {
54 if (mDisplay != EGL_NO_DISPLAY)
55 {
56 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
57
58 if (mWindowSurface != EGL_NO_SURFACE)
59 {
60 eglDestroySurface(mDisplay, mWindowSurface);
61 mWindowSurface = EGL_NO_SURFACE;
62 }
63
64 if (mPbufferSurface != EGL_NO_SURFACE)
65 {
66 eglDestroySurface(mDisplay, mPbufferSurface);
67 mPbufferSurface = EGL_NO_SURFACE;
68 }
69
70 if (mContext != EGL_NO_CONTEXT)
71 {
72 eglDestroyContext(mDisplay, mContext);
73 mContext = EGL_NO_CONTEXT;
74 }
75
76 if (mSecondContext != EGL_NO_CONTEXT)
77 {
78 eglDestroyContext(mDisplay, mSecondContext);
79 mSecondContext = EGL_NO_CONTEXT;
80 }
81
82 eglTerminate(mDisplay);
83 mDisplay = EGL_NO_DISPLAY;
84 }
85
86 mOSWindow->destroy();
87 OSWindow::Delete(&mOSWindow);
88
89 ASSERT_TRUE(mWindowSurface == EGL_NO_SURFACE && mContext == EGL_NO_CONTEXT);
90 }
91
initializeDisplay()92 void initializeDisplay()
93 {
94 GLenum platformType = GetParam().getRenderer();
95 GLenum deviceType = GetParam().getDeviceType();
96
97 std::vector<EGLint> displayAttributes;
98 displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
99 displayAttributes.push_back(platformType);
100 displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
101 displayAttributes.push_back(EGL_DONT_CARE);
102 displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
103 displayAttributes.push_back(EGL_DONT_CARE);
104 displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
105 displayAttributes.push_back(deviceType);
106 displayAttributes.push_back(EGL_NONE);
107
108 mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
109 reinterpret_cast<void *>(mOSWindow->getNativeDisplay()),
110 displayAttributes.data());
111 ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
112
113 EGLint majorVersion, minorVersion;
114 ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE);
115
116 eglBindAPI(EGL_OPENGL_ES_API);
117 ASSERT_EGL_SUCCESS();
118 }
119
initializeContext()120 void initializeContext()
121 {
122 EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, GetParam().majorVersion, EGL_NONE};
123
124 mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
125 ASSERT_EGL_SUCCESS();
126
127 mSecondContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
128 ASSERT_EGL_SUCCESS();
129 }
130
initializeSurface(EGLConfig config)131 void initializeSurface(EGLConfig config)
132 {
133 mConfig = config;
134
135 std::vector<EGLint> windowAttributes;
136 windowAttributes.push_back(EGL_NONE);
137
138 // Create first window surface
139 mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(),
140 windowAttributes.data());
141 ASSERT_EGL_SUCCESS();
142
143 // Give pbuffer non-zero dimensions.
144 std::vector<EGLint> pbufferAttributes;
145 pbufferAttributes.push_back(EGL_WIDTH);
146 pbufferAttributes.push_back(64);
147 pbufferAttributes.push_back(EGL_HEIGHT);
148 pbufferAttributes.push_back(64);
149 pbufferAttributes.push_back(EGL_NONE);
150
151 mPbufferSurface = eglCreatePbufferSurface(mDisplay, mConfig, pbufferAttributes.data());
152 ASSERT_EGL_SUCCESS();
153 initializeContext();
154 }
155
initializeSurfaceWithDefaultConfig()156 void initializeSurfaceWithDefaultConfig()
157 {
158 const EGLint configAttributes[] = {EGL_RED_SIZE,
159 EGL_DONT_CARE,
160 EGL_GREEN_SIZE,
161 EGL_DONT_CARE,
162 EGL_BLUE_SIZE,
163 EGL_DONT_CARE,
164 EGL_ALPHA_SIZE,
165 EGL_DONT_CARE,
166 EGL_DEPTH_SIZE,
167 EGL_DONT_CARE,
168 EGL_STENCIL_SIZE,
169 EGL_DONT_CARE,
170 EGL_SAMPLE_BUFFERS,
171 0,
172 EGL_NONE};
173
174 EGLint configCount;
175 EGLConfig config;
176 ASSERT_TRUE(eglChooseConfig(mDisplay, configAttributes, &config, 1, &configCount) ||
177 (configCount != 1) == EGL_TRUE);
178
179 initializeSurface(config);
180 }
181
createProgram()182 GLuint createProgram()
183 {
184 return CompileProgram(angle::essl1_shaders::vs::Simple(), angle::essl1_shaders::fs::Red());
185 }
186
drawWithProgram(GLuint program)187 void drawWithProgram(GLuint program)
188 {
189 glClearColor(0, 0, 0, 1);
190 glClear(GL_COLOR_BUFFER_BIT);
191
192 GLint positionLocation =
193 glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib());
194
195 glUseProgram(program);
196
197 const GLfloat vertices[] = {
198 -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
199
200 -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
201 };
202
203 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
204 glEnableVertexAttribArray(positionLocation);
205
206 glDrawArrays(GL_TRIANGLES, 0, 6);
207
208 glDisableVertexAttribArray(positionLocation);
209 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
210
211 EXPECT_PIXEL_EQ(mOSWindow->getWidth() / 2, mOSWindow->getHeight() / 2, 255, 0, 0, 255);
212 }
213
runMessageLoopTest(EGLSurface secondSurface,EGLContext secondContext)214 void runMessageLoopTest(EGLSurface secondSurface, EGLContext secondContext)
215 {
216 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
217 ASSERT_EGL_SUCCESS();
218
219 // Make a second context current
220 eglMakeCurrent(mDisplay, secondSurface, secondSurface, secondContext);
221 eglDestroySurface(mDisplay, mWindowSurface);
222
223 // Create second window surface
224 std::vector<EGLint> surfaceAttributes;
225 surfaceAttributes.push_back(EGL_NONE);
226 surfaceAttributes.push_back(EGL_NONE);
227
228 mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(),
229 &surfaceAttributes[0]);
230 ASSERT_EGL_SUCCESS();
231
232 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
233 ASSERT_EGL_SUCCESS();
234
235 mOSWindow->signalTestEvent();
236 mOSWindow->messageLoop();
237 ASSERT_TRUE(mOSWindow->didTestEventFire());
238
239 // Simple operation to test the FBO is set appropriately
240 glClear(GL_COLOR_BUFFER_BIT);
241 }
242
243 EGLDisplay mDisplay;
244 EGLSurface mWindowSurface;
245 EGLSurface mPbufferSurface;
246 EGLContext mContext;
247 EGLContext mSecondContext;
248 EGLConfig mConfig;
249 OSWindow *mOSWindow;
250 };
251
252 class EGLFloatSurfaceTest : public EGLSurfaceTest
253 {
254 protected:
EGLFloatSurfaceTest()255 EGLFloatSurfaceTest() : EGLSurfaceTest()
256 {
257 setWindowWidth(512);
258 setWindowHeight(512);
259 }
260
testSetUp()261 void testSetUp() override
262 {
263 mOSWindow = OSWindow::New();
264 mOSWindow->initialize("EGLFloatSurfaceTest", 64, 64);
265 }
266
testTearDown()267 void testTearDown() override
268 {
269 EGLSurfaceTest::testTearDown();
270 glDeleteProgram(mProgram);
271 }
272
createProgram()273 GLuint createProgram()
274 {
275 constexpr char kFS[] =
276 "precision highp float;\n"
277 "void main()\n"
278 "{\n"
279 " gl_FragColor = vec4(1.0, 2.0, 3.0, 4.0);\n"
280 "}\n";
281 return CompileProgram(angle::essl1_shaders::vs::Simple(), kFS);
282 }
283
initializeSurfaceWithFloatConfig()284 bool initializeSurfaceWithFloatConfig()
285 {
286 const EGLint configAttributes[] = {EGL_RED_SIZE,
287 16,
288 EGL_GREEN_SIZE,
289 16,
290 EGL_BLUE_SIZE,
291 16,
292 EGL_ALPHA_SIZE,
293 16,
294 EGL_COLOR_COMPONENT_TYPE_EXT,
295 EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
296 EGL_NONE,
297 EGL_NONE};
298
299 initializeDisplay();
300 EGLConfig config;
301 if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
302 {
303 std::cout << "EGLConfig for a float surface is not supported, skipping test"
304 << std::endl;
305 return false;
306 }
307
308 initializeSurface(config);
309
310 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
311 mProgram = createProgram();
312 return true;
313 }
314
315 GLuint mProgram;
316 };
317
318 // Test clearing and checking the color is correct
TEST_P(EGLFloatSurfaceTest,Clearing)319 TEST_P(EGLFloatSurfaceTest, Clearing)
320 {
321 ANGLE_SKIP_TEST_IF(!initializeSurfaceWithFloatConfig());
322
323 ASSERT_NE(0u, mProgram) << "shader compilation failed.";
324 ASSERT_GL_NO_ERROR();
325
326 GLColor32F clearColor(0.0f, 1.0f, 2.0f, 3.0f);
327 glClearColor(clearColor.R, clearColor.G, clearColor.B, clearColor.A);
328 glClear(GL_COLOR_BUFFER_BIT);
329 ASSERT_GL_NO_ERROR();
330
331 EXPECT_PIXEL_COLOR32F_EQ(0, 0, clearColor);
332 }
333
334 // Test drawing and checking the color is correct
TEST_P(EGLFloatSurfaceTest,Drawing)335 TEST_P(EGLFloatSurfaceTest, Drawing)
336 {
337 ANGLE_SKIP_TEST_IF(!initializeSurfaceWithFloatConfig());
338
339 ASSERT_NE(0u, mProgram) << "shader compilation failed.";
340 ASSERT_GL_NO_ERROR();
341
342 glUseProgram(mProgram);
343 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
344
345 EXPECT_PIXEL_32F_EQ(0, 0, 1.0f, 2.0f, 3.0f, 4.0f);
346 }
347
348 class EGLSurfaceTest3 : public EGLSurfaceTest
349 {};
350
351 // Test a surface bug where we could have two Window surfaces active
352 // at one time, blocking message loops. See http://crbug.com/475085
TEST_P(EGLSurfaceTest,MessageLoopBug)353 TEST_P(EGLSurfaceTest, MessageLoopBug)
354 {
355 // TODO(syoussefi): http://anglebug.com/3123
356 ANGLE_SKIP_TEST_IF(IsAndroid());
357
358 // http://anglebug.com/3138
359 ANGLE_SKIP_TEST_IF(IsOzone());
360
361 initializeDisplay();
362 initializeSurfaceWithDefaultConfig();
363
364 runMessageLoopTest(EGL_NO_SURFACE, EGL_NO_CONTEXT);
365 }
366
367 // Tests the message loop bug, but with setting a second context
368 // instead of null.
TEST_P(EGLSurfaceTest,MessageLoopBugContext)369 TEST_P(EGLSurfaceTest, MessageLoopBugContext)
370 {
371 // TODO(syoussefi): http://anglebug.com/3123
372 ANGLE_SKIP_TEST_IF(IsAndroid());
373
374 // http://anglebug.com/3138
375 ANGLE_SKIP_TEST_IF(IsOzone());
376
377 initializeDisplay();
378 initializeSurfaceWithDefaultConfig();
379
380 runMessageLoopTest(mPbufferSurface, mSecondContext);
381 }
382
383 // Test a bug where calling makeCurrent twice would release the surface
TEST_P(EGLSurfaceTest,MakeCurrentTwice)384 TEST_P(EGLSurfaceTest, MakeCurrentTwice)
385 {
386 initializeDisplay();
387 initializeSurfaceWithDefaultConfig();
388
389 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
390 ASSERT_EGL_SUCCESS();
391
392 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
393 ASSERT_EGL_SUCCESS();
394
395 // Simple operation to test the FBO is set appropriately
396 glClear(GL_COLOR_BUFFER_BIT);
397 }
398
399 // Test that the window surface is correctly resized after calling swapBuffers
TEST_P(EGLSurfaceTest,ResizeWindow)400 TEST_P(EGLSurfaceTest, ResizeWindow)
401 {
402 // http://anglebug.com/4453
403 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel());
404 // Flaky on Linux SwANGLE http://anglebug.com/4453
405 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader());
406
407 // Necessary for a window resizing test if there is no per-frame window size query
408 setWindowVisible(mOSWindow, true);
409
410 GLenum platform = GetParam().getRenderer();
411 bool platformSupportsZeroSize = platform == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ||
412 platform == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
413 int minSize = platformSupportsZeroSize ? 0 : 1;
414
415 initializeDisplay();
416 initializeSurfaceWithDefaultConfig();
417 initializeContext();
418
419 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
420 eglSwapBuffers(mDisplay, mWindowSurface);
421 ASSERT_EGL_SUCCESS();
422
423 EGLint height;
424 eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
425 ASSERT_EGL_SUCCESS();
426 ASSERT_EQ(64, height); // initial size
427
428 // set window's height to 0 (if possible) or 1
429 mOSWindow->resize(64, minSize);
430
431 eglSwapBuffers(mDisplay, mWindowSurface);
432 ASSERT_EGL_SUCCESS();
433
434 // TODO(syoussefi): the GLX implementation still reads the window size as 64x64 through
435 // XGetGeometry. http://anglebug.com/3122
436 ANGLE_SKIP_TEST_IF(IsLinux() && IsOpenGL());
437
438 eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
439 ASSERT_EGL_SUCCESS();
440 ASSERT_EQ(minSize, height);
441
442 // restore window's height
443 mOSWindow->resize(64, 64);
444
445 eglSwapBuffers(mDisplay, mWindowSurface);
446 ASSERT_EGL_SUCCESS();
447
448 eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
449 ASSERT_EGL_SUCCESS();
450 ASSERT_EQ(64, height);
451 }
452
453 // Test that the backbuffer is correctly resized after calling swapBuffers
TEST_P(EGLSurfaceTest,ResizeWindowWithDraw)454 TEST_P(EGLSurfaceTest, ResizeWindowWithDraw)
455 {
456 // http://anglebug.com/4453
457 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel());
458
459 // Flaky on Linux SwANGLE http://anglebug.com/4453
460 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader());
461
462 // Necessary for a window resizing test if there is no per-frame window size query
463 setWindowVisible(mOSWindow, true);
464
465 initializeDisplay();
466 initializeSurfaceWithDefaultConfig();
467 initializeContext();
468
469 int size = 64;
470 EGLint height = 0;
471 EGLint width = 0;
472
473 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
474 eglSwapBuffers(mDisplay, mWindowSurface);
475 ASSERT_EGL_SUCCESS();
476
477 // Clear to red
478 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
479 glClear(GL_COLOR_BUFFER_BIT);
480
481 eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
482 eglQuerySurface(mDisplay, mWindowSurface, EGL_WIDTH, &width);
483 ASSERT_EGL_SUCCESS();
484
485 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
486 EXPECT_PIXEL_COLOR_EQ(size - 1, 0, GLColor::red);
487 EXPECT_PIXEL_COLOR_EQ(size - 1, size - 1, GLColor::red);
488 EXPECT_PIXEL_COLOR_EQ(0, size - 1, GLColor::red);
489 EXPECT_PIXEL_COLOR_EQ(-1, -1, GLColor::transparentBlack);
490 EXPECT_PIXEL_COLOR_EQ(size, 0, GLColor::transparentBlack);
491 EXPECT_PIXEL_COLOR_EQ(0, size, GLColor::transparentBlack);
492 EXPECT_PIXEL_COLOR_EQ(size, size, GLColor::transparentBlack);
493
494 // set window's size small
495 size = 1;
496 mOSWindow->resize(size, size);
497
498 eglSwapBuffers(mDisplay, mWindowSurface);
499 ASSERT_EGL_SUCCESS();
500
501 // Clear to green
502 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
503 glClear(GL_COLOR_BUFFER_BIT);
504
505 eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
506 eglQuerySurface(mDisplay, mWindowSurface, EGL_WIDTH, &width);
507 ASSERT_EGL_SUCCESS();
508
509 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
510 EXPECT_PIXEL_COLOR_EQ(size - 1, 0, GLColor::green);
511 EXPECT_PIXEL_COLOR_EQ(size - 1, size - 1, GLColor::green);
512 EXPECT_PIXEL_COLOR_EQ(0, size - 1, GLColor::green);
513 EXPECT_PIXEL_COLOR_EQ(-1, -1, GLColor::transparentBlack);
514 EXPECT_PIXEL_COLOR_EQ(size, 0, GLColor::transparentBlack);
515 EXPECT_PIXEL_COLOR_EQ(0, size, GLColor::transparentBlack);
516 EXPECT_PIXEL_COLOR_EQ(size, size, GLColor::transparentBlack);
517
518 // set window's height large
519 size = 128;
520 mOSWindow->resize(size, size);
521
522 eglSwapBuffers(mDisplay, mWindowSurface);
523 ASSERT_EGL_SUCCESS();
524
525 // Clear to blue
526 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
527 glClear(GL_COLOR_BUFFER_BIT);
528
529 eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
530 eglQuerySurface(mDisplay, mWindowSurface, EGL_WIDTH, &width);
531 ASSERT_EGL_SUCCESS();
532
533 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
534 EXPECT_PIXEL_COLOR_EQ(size - 1, 0, GLColor::blue);
535 EXPECT_PIXEL_COLOR_EQ(size - 1, size - 1, GLColor::blue);
536 EXPECT_PIXEL_COLOR_EQ(0, size - 1, GLColor::blue);
537 EXPECT_PIXEL_COLOR_EQ(-1, -1, GLColor::transparentBlack);
538 EXPECT_PIXEL_COLOR_EQ(size, 0, GLColor::transparentBlack);
539 EXPECT_PIXEL_COLOR_EQ(0, size, GLColor::transparentBlack);
540 EXPECT_PIXEL_COLOR_EQ(size, size, GLColor::transparentBlack);
541 }
542
543 // Test that the window can be reset repeatedly before surface creation.
TEST_P(EGLSurfaceTest,ResetNativeWindow)544 TEST_P(EGLSurfaceTest, ResetNativeWindow)
545 {
546 setWindowVisible(mOSWindow, true);
547
548 initializeDisplay();
549
550 for (int i = 0; i < 10; ++i)
551 {
552 mOSWindow->resetNativeWindow();
553 }
554
555 initializeSurfaceWithDefaultConfig();
556 initializeContext();
557
558 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
559
560 eglSwapBuffers(mDisplay, mWindowSurface);
561 ASSERT_EGL_SUCCESS();
562 }
563
564 // Test creating a surface that supports a EGLConfig with 16bit
565 // support GL_RGB565
TEST_P(EGLSurfaceTest,CreateWithEGLConfig5650Support)566 TEST_P(EGLSurfaceTest, CreateWithEGLConfig5650Support)
567 {
568 const EGLint configAttributes[] = {
569 EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 0,
570 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
571
572 initializeDisplay();
573 EGLConfig config;
574 if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
575 {
576 std::cout << "EGLConfig for a GL_RGB565 surface is not supported, skipping test"
577 << std::endl;
578 return;
579 }
580
581 initializeSurface(config);
582
583 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
584 ASSERT_EGL_SUCCESS();
585
586 GLuint program = createProgram();
587 ASSERT_NE(0u, program);
588 drawWithProgram(program);
589 EXPECT_GL_NO_ERROR();
590 glDeleteProgram(program);
591 }
592
593 // Test creating a surface that supports a EGLConfig with 16bit
594 // support GL_RGBA4
TEST_P(EGLSurfaceTest,CreateWithEGLConfig4444Support)595 TEST_P(EGLSurfaceTest, CreateWithEGLConfig4444Support)
596 {
597 const EGLint configAttributes[] = {
598 EGL_RED_SIZE, 4, EGL_GREEN_SIZE, 4, EGL_BLUE_SIZE, 4, EGL_ALPHA_SIZE, 4,
599 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
600
601 initializeDisplay();
602 EGLConfig config;
603 if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
604 {
605 std::cout << "EGLConfig for a GL_RGBA4 surface is not supported, skipping test"
606 << std::endl;
607 return;
608 }
609
610 initializeSurface(config);
611
612 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
613 ASSERT_EGL_SUCCESS();
614
615 GLuint program = createProgram();
616 ASSERT_NE(0u, program);
617 drawWithProgram(program);
618 EXPECT_GL_NO_ERROR();
619 glDeleteProgram(program);
620 }
621
622 // Test creating a surface that supports a EGLConfig with 16bit
623 // support GL_RGB5_A1
TEST_P(EGLSurfaceTest,CreateWithEGLConfig5551Support)624 TEST_P(EGLSurfaceTest, CreateWithEGLConfig5551Support)
625 {
626 const EGLint configAttributes[] = {
627 EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 5, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 1,
628 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
629
630 initializeDisplay();
631 EGLConfig config;
632 if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
633 {
634 std::cout << "EGLConfig for a GL_RGB5_A1 surface is not supported, skipping test"
635 << std::endl;
636 return;
637 }
638
639 initializeSurface(config);
640
641 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
642 ASSERT_EGL_SUCCESS();
643
644 GLuint program = createProgram();
645 ASSERT_NE(0u, program);
646 drawWithProgram(program);
647 EXPECT_GL_NO_ERROR();
648 glDeleteProgram(program);
649 }
650
651 // Test creating a surface that supports a EGLConfig without alpha support
TEST_P(EGLSurfaceTest,CreateWithEGLConfig8880Support)652 TEST_P(EGLSurfaceTest, CreateWithEGLConfig8880Support)
653 {
654 const EGLint configAttributes[] = {
655 EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0,
656 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
657
658 initializeDisplay();
659 EGLConfig config;
660 if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
661 {
662 std::cout << "EGLConfig for a GL_RGB8_OES surface is not supported, skipping test"
663 << std::endl;
664 return;
665 }
666
667 initializeSurface(config);
668
669 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
670 ASSERT_EGL_SUCCESS();
671
672 GLuint program = createProgram();
673 ASSERT_NE(0u, program);
674 drawWithProgram(program);
675 EXPECT_GL_NO_ERROR();
676 glDeleteProgram(program);
677 }
678
TEST_P(EGLSurfaceTest,FixedSizeWindow)679 TEST_P(EGLSurfaceTest, FixedSizeWindow)
680 {
681 const EGLint configAttributes[] = {
682 EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0,
683 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
684
685 initializeDisplay();
686 ANGLE_SKIP_TEST_IF(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &mConfig) == EGL_FALSE);
687
688 ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANGLE_window_fixed_size"));
689
690 constexpr EGLint kInitialSize = 64;
691 constexpr EGLint kUpdateSize = 32;
692
693 EGLint surfaceAttributes[] = {
694 EGL_FIXED_SIZE_ANGLE, EGL_TRUE, EGL_WIDTH, kInitialSize, EGL_HEIGHT, kInitialSize, EGL_NONE,
695 };
696
697 // Create first window surface
698 mWindowSurface =
699 eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), surfaceAttributes);
700 ASSERT_EGL_SUCCESS();
701 ASSERT_NE(EGL_NO_SURFACE, mWindowSurface);
702
703 initializeContext();
704 EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext));
705 ASSERT_EGL_SUCCESS();
706
707 EGLint queryIsFixedSize = 0;
708 EXPECT_EGL_TRUE(
709 eglQuerySurface(mDisplay, mWindowSurface, EGL_FIXED_SIZE_ANGLE, &queryIsFixedSize));
710 ASSERT_EGL_SUCCESS();
711 EXPECT_EGL_TRUE(queryIsFixedSize);
712
713 EGLint queryWidth = 0;
714 EXPECT_EGL_TRUE(eglQuerySurface(mDisplay, mWindowSurface, EGL_WIDTH, &queryWidth));
715 ASSERT_EGL_SUCCESS();
716 EXPECT_EQ(kInitialSize, queryWidth);
717
718 EGLint queryHeight = 0;
719 EXPECT_EGL_TRUE(eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &queryHeight));
720 ASSERT_EGL_SUCCESS();
721 EXPECT_EQ(kInitialSize, queryHeight);
722
723 // Update the size
724 EXPECT_EGL_TRUE(eglSurfaceAttrib(mDisplay, mWindowSurface, EGL_WIDTH, kUpdateSize));
725 ASSERT_EGL_SUCCESS();
726
727 EXPECT_EGL_TRUE(eglWaitNative(EGL_CORE_NATIVE_ENGINE));
728 ASSERT_EGL_SUCCESS();
729
730 EGLint queryUpdatedWidth = 0;
731 EXPECT_EGL_TRUE(eglQuerySurface(mDisplay, mWindowSurface, EGL_WIDTH, &queryUpdatedWidth));
732 ASSERT_EGL_SUCCESS();
733 EXPECT_EQ(kUpdateSize, queryUpdatedWidth);
734 }
735
TEST_P(EGLSurfaceTest3,MakeCurrentDifferentSurfaces)736 TEST_P(EGLSurfaceTest3, MakeCurrentDifferentSurfaces)
737 {
738 const EGLint configAttributes[] = {
739 EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
740 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
741 EGLSurface firstPbufferSurface;
742 EGLSurface secondPbufferSurface;
743
744 initializeDisplay();
745 ANGLE_SKIP_TEST_IF(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &mConfig) == EGL_FALSE);
746
747 EGLint surfaceType = 0;
748 eglGetConfigAttrib(mDisplay, mConfig, EGL_SURFACE_TYPE, &surfaceType);
749 bool supportsPbuffers = (surfaceType & EGL_PBUFFER_BIT) != 0;
750 EGLint bindToTextureRGBA = 0;
751 eglGetConfigAttrib(mDisplay, mConfig, EGL_BIND_TO_TEXTURE_RGBA, &bindToTextureRGBA);
752 bool supportsBindTexImage = (bindToTextureRGBA == EGL_TRUE);
753
754 const EGLint pBufferAttributes[] = {
755 EGL_WIDTH, 64,
756 EGL_HEIGHT, 64,
757 EGL_TEXTURE_FORMAT, supportsPbuffers ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
758 EGL_TEXTURE_TARGET, supportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
759 EGL_NONE, EGL_NONE,
760 };
761
762 // Create the surfaces
763 firstPbufferSurface = eglCreatePbufferSurface(mDisplay, mConfig, pBufferAttributes);
764 ASSERT_EGL_SUCCESS();
765 ASSERT_NE(EGL_NO_SURFACE, firstPbufferSurface);
766 secondPbufferSurface = eglCreatePbufferSurface(mDisplay, mConfig, pBufferAttributes);
767 ASSERT_EGL_SUCCESS();
768 ASSERT_NE(EGL_NO_SURFACE, secondPbufferSurface);
769
770 initializeContext();
771
772 // Use the same surface for both draw and read
773 EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, firstPbufferSurface, firstPbufferSurface, mContext));
774 glClearColor(GLColor::red.R, GLColor::red.G, GLColor::red.B, GLColor::red.A);
775 glClear(GL_COLOR_BUFFER_BIT);
776 ASSERT_GL_NO_ERROR();
777 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
778
779 // Use different surfaces for draw and read, read should stay the same
780 EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, secondPbufferSurface, firstPbufferSurface, mContext));
781 glClearColor(GLColor::blue.R, GLColor::blue.G, GLColor::blue.B, GLColor::blue.A);
782 glClear(GL_COLOR_BUFFER_BIT);
783 ASSERT_GL_NO_ERROR();
784 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
785 // Verify draw surface was cleared
786 EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, secondPbufferSurface, secondPbufferSurface, mContext));
787 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
788
789 EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, firstPbufferSurface, secondPbufferSurface, mContext));
790 ASSERT_EGL_SUCCESS();
791
792 // Blit the source surface to the destination surface
793 glBlitFramebuffer(0, 0, 64, 64, 0, 0, 64, 64, GL_COLOR_BUFFER_BIT, GL_NEAREST);
794 ASSERT_GL_NO_ERROR();
795 EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, firstPbufferSurface, firstPbufferSurface, mContext));
796 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
797 }
798
799 #if defined(ANGLE_ENABLE_D3D11)
800 class EGLSurfaceTestD3D11 : public EGLSurfaceTest
801 {};
802
803 // Test that rendering to an IDCompositionSurface using a pbuffer works.
TEST_P(EGLSurfaceTestD3D11,CreateDirectCompositionSurface)804 TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
805 {
806 ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
807 initializeDisplay();
808
809 EGLAttrib device = 0;
810 EGLAttrib newEglDevice = 0;
811 ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));
812 ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),
813 EGL_D3D11_DEVICE_ANGLE, &device));
814 angle::ComPtr<ID3D11Device> d3d11Device(reinterpret_cast<ID3D11Device *>(device));
815 ASSERT_TRUE(!!d3d11Device);
816
817 HMODULE dcompLibrary = LoadLibraryA("dcomp.dll");
818 if (!dcompLibrary)
819 {
820 std::cout << "DirectComposition not supported" << std::endl;
821 return;
822 }
823 typedef HRESULT(WINAPI * PFN_DCOMPOSITION_CREATE_DEVICE2)(IUnknown * dxgiDevice, REFIID iid,
824 void **dcompositionDevice);
825 PFN_DCOMPOSITION_CREATE_DEVICE2 createDComp = reinterpret_cast<PFN_DCOMPOSITION_CREATE_DEVICE2>(
826 GetProcAddress(dcompLibrary, "DCompositionCreateDevice2"));
827 if (!createDComp)
828 {
829 std::cout << "DirectComposition2 not supported" << std::endl;
830 FreeLibrary(dcompLibrary);
831 return;
832 }
833
834 angle::ComPtr<IDCompositionDevice> dcompDevice;
835 HRESULT hr = createDComp(d3d11Device.Get(), IID_PPV_ARGS(dcompDevice.GetAddressOf()));
836 ASSERT_TRUE(SUCCEEDED(hr));
837
838 angle::ComPtr<IDCompositionSurface> dcompSurface;
839 hr = dcompDevice->CreateSurface(100, 100, DXGI_FORMAT_B8G8R8A8_UNORM,
840 DXGI_ALPHA_MODE_PREMULTIPLIED, dcompSurface.GetAddressOf());
841 ASSERT_TRUE(SUCCEEDED(hr));
842
843 angle::ComPtr<ID3D11Texture2D> texture;
844 POINT updateOffset;
845 hr = dcompSurface->BeginDraw(nullptr, IID_PPV_ARGS(texture.GetAddressOf()), &updateOffset);
846 ASSERT_TRUE(SUCCEEDED(hr));
847
848 const EGLint configAttributes[] = {
849 EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
850 EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
851
852 EGLConfig config;
853 ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config));
854
855 const EGLint surfaceAttributes[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
856
857 EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get());
858 mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
859 config, surfaceAttributes);
860 ASSERT_EGL_SUCCESS();
861
862 mConfig = config;
863 initializeContext();
864
865 eglMakeCurrent(mDisplay, mPbufferSurface, mPbufferSurface, mContext);
866 ASSERT_EGL_SUCCESS();
867
868 GLuint program = createProgram();
869 ASSERT_NE(0u, program);
870 drawWithProgram(program);
871 EXPECT_GL_NO_ERROR();
872 glDeleteProgram(program);
873 }
874
TEST_P(EGLSurfaceTestD3D11,CreateSurfaceWithMSAA)875 TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithMSAA)
876 {
877 ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
878
879 // clang-format off
880 const EGLint configAttributes[] =
881 {
882 EGL_RED_SIZE, 8,
883 EGL_GREEN_SIZE, 8,
884 EGL_BLUE_SIZE, 8,
885 EGL_ALPHA_SIZE, 0,
886 EGL_DEPTH_SIZE, 0,
887 EGL_STENCIL_SIZE, 0,
888 EGL_SAMPLE_BUFFERS, 1,
889 EGL_SAMPLES, 4,
890 EGL_NONE
891 };
892 // clang-format on
893
894 initializeDisplay();
895 EGLConfig config;
896 if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
897 {
898 std::cout << "EGLConfig for 4xMSAA is not supported, skipping test" << std::endl;
899 return;
900 }
901
902 initializeSurface(config);
903
904 eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
905 ASSERT_EGL_SUCCESS();
906
907 GLuint program = createProgram();
908 ASSERT_NE(0u, program);
909
910 glClearColor(0, 0, 0, 1);
911 glClear(GL_COLOR_BUFFER_BIT);
912
913 GLint positionLocation = glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib());
914 ASSERT_NE(-1, positionLocation);
915
916 glUseProgram(program);
917
918 const GLfloat halfPixelOffset = 0.5f * 2.0f / mOSWindow->getWidth();
919 // clang-format off
920 const GLfloat vertices[] =
921 {
922 -1.0f + halfPixelOffset, 1.0f, 0.5f,
923 -1.0f + halfPixelOffset, -1.0f, 0.5f,
924 1.0f, -1.0f, 0.5f
925 };
926 // clang-format on
927
928 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
929 glEnableVertexAttribArray(positionLocation);
930
931 glDrawArrays(GL_TRIANGLES, 0, 3);
932
933 glDisableVertexAttribArray(positionLocation);
934 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
935
936 EXPECT_PIXEL_NEAR(0, 0, 127, 0, 0, 255, 10);
937 EXPECT_GL_NO_ERROR();
938
939 glDeleteProgram(program);
940 }
941
942 #endif // ANGLE_ENABLE_D3D11
943
944 } // anonymous namespace
945
946 ANGLE_INSTANTIATE_TEST(EGLSurfaceTest,
947 WithNoFixture(ES2_D3D9()),
948 WithNoFixture(ES2_D3D11()),
949 WithNoFixture(ES3_D3D11()),
950 WithNoFixture(ES2_OPENGL()),
951 WithNoFixture(ES3_OPENGL()),
952 WithNoFixture(ES2_OPENGLES()),
953 WithNoFixture(ES3_OPENGLES()),
954 WithNoFixture(ES2_VULKAN()),
955 WithNoFixture(ES3_VULKAN()),
956 WithNoFixture(ES2_VULKAN_SWIFTSHADER()),
957 WithNoFixture(ES3_VULKAN_SWIFTSHADER()));
958 ANGLE_INSTANTIATE_TEST(EGLFloatSurfaceTest,
959 WithNoFixture(ES2_OPENGL()),
960 WithNoFixture(ES3_OPENGL()),
961 WithNoFixture(ES2_VULKAN()),
962 WithNoFixture(ES3_VULKAN()));
963 ANGLE_INSTANTIATE_TEST(EGLSurfaceTest3, WithNoFixture(ES3_VULKAN()));
964
965 #if defined(ANGLE_ENABLE_D3D11)
966 ANGLE_INSTANTIATE_TEST(EGLSurfaceTestD3D11, WithNoFixture(ES2_D3D11()), WithNoFixture(ES3_D3D11()));
967 #endif
968