• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 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 //    EGLIOSurfaceClientBufferTest.cpp: tests for the EGL_ANGLE_iosurface_client_buffer extension.
7 //
8 
9 #include "test_utils/ANGLETest.h"
10 
11 #include "common/mathutil.h"
12 #include "test_utils/gl_raii.h"
13 #include "util/EGLWindow.h"
14 
15 #include <CoreFoundation/CoreFoundation.h>
16 #include <IOSurface/IOSurface.h>
17 
18 using namespace angle;
19 
20 namespace
21 {
22 
23 constexpr char kIOSurfaceExt[] = "EGL_ANGLE_iosurface_client_buffer";
24 
AddIntegerValue(CFMutableDictionaryRef dictionary,const CFStringRef key,int32_t value)25 void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, int32_t value)
26 {
27     CFNumberRef number = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value);
28     CFDictionaryAddValue(dictionary, key, number);
29     CFRelease(number);
30 }
31 
32 class ScopedIOSurfaceRef : angle::NonCopyable
33 {
34   public:
ScopedIOSurfaceRef(IOSurfaceRef surface)35     explicit ScopedIOSurfaceRef(IOSurfaceRef surface) : mSurface(surface) {}
36 
~ScopedIOSurfaceRef()37     ~ScopedIOSurfaceRef()
38     {
39         if (mSurface != nullptr)
40         {
41             CFRelease(mSurface);
42             mSurface = nullptr;
43         }
44     }
45 
get() const46     IOSurfaceRef get() const { return mSurface; }
47 
ScopedIOSurfaceRef(ScopedIOSurfaceRef && other)48     ScopedIOSurfaceRef(ScopedIOSurfaceRef &&other)
49     {
50         if (mSurface != nullptr)
51         {
52             CFRelease(mSurface);
53         }
54         mSurface       = other.mSurface;
55         other.mSurface = nullptr;
56     }
57 
operator =(ScopedIOSurfaceRef && other)58     ScopedIOSurfaceRef &operator=(ScopedIOSurfaceRef &&other)
59     {
60         if (mSurface != nullptr)
61         {
62             CFRelease(mSurface);
63         }
64         mSurface       = other.mSurface;
65         other.mSurface = nullptr;
66 
67         return *this;
68     }
69 
70   private:
71     IOSurfaceRef mSurface = nullptr;
72 };
73 
CreateSinglePlaneIOSurface(int width,int height,int32_t format,int bytesPerElement)74 ScopedIOSurfaceRef CreateSinglePlaneIOSurface(int width,
75                                               int height,
76                                               int32_t format,
77                                               int bytesPerElement)
78 {
79     CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
80         kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
81     AddIntegerValue(dict, kIOSurfaceWidth, width);
82     AddIntegerValue(dict, kIOSurfaceHeight, height);
83     AddIntegerValue(dict, kIOSurfacePixelFormat, format);
84     AddIntegerValue(dict, kIOSurfaceBytesPerElement, bytesPerElement);
85 
86     IOSurfaceRef ioSurface = IOSurfaceCreate(dict);
87     EXPECT_NE(nullptr, ioSurface);
88     CFRelease(dict);
89 
90     return ScopedIOSurfaceRef(ioSurface);
91 }
92 
93 }  // anonymous namespace
94 
95 class IOSurfaceClientBufferTest : public ANGLETest
96 {
97   protected:
getTextureTarget() const98     EGLint getTextureTarget() const
99     {
100         EGLint target = 0;
101         eglGetConfigAttrib(mDisplay, mConfig, EGL_BIND_TO_TEXTURE_TARGET_ANGLE, &target);
102         return target;
103     }
104 
getGLTextureTarget() const105     GLint getGLTextureTarget() const
106     {
107         EGLint targetEGL = getTextureTarget();
108         GLenum targetGL  = 0;
109         switch (targetEGL)
110         {
111             case EGL_TEXTURE_2D:
112                 targetGL = GL_TEXTURE_2D;
113                 break;
114             case EGL_TEXTURE_RECTANGLE_ANGLE:
115                 targetGL = GL_TEXTURE_RECTANGLE_ANGLE;
116                 break;
117             default:
118                 break;
119         }
120         return targetGL;
121     }
122 
IOSurfaceClientBufferTest()123     IOSurfaceClientBufferTest() : mConfig(0), mDisplay(nullptr) {}
124 
testSetUp()125     void testSetUp() override
126     {
127         mConfig  = getEGLWindow()->getConfig();
128         mDisplay = getEGLWindow()->getDisplay();
129     }
130 
createIOSurfacePbuffer(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,EGLSurface * pbuffer) const131     void createIOSurfacePbuffer(const ScopedIOSurfaceRef &ioSurface,
132                                 EGLint width,
133                                 EGLint height,
134                                 EGLint plane,
135                                 GLenum internalFormat,
136                                 GLenum type,
137                                 EGLSurface *pbuffer) const
138     {
139         // clang-format off
140         const EGLint attribs[] = {
141             EGL_WIDTH,                         width,
142             EGL_HEIGHT,                        height,
143             EGL_IOSURFACE_PLANE_ANGLE,         plane,
144             EGL_TEXTURE_TARGET,                getTextureTarget(),
145             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, internalFormat,
146             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
147             EGL_TEXTURE_TYPE_ANGLE,            type,
148             EGL_NONE,                          EGL_NONE,
149         };
150         // clang-format on
151 
152         *pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(),
153                                                     mConfig, attribs);
154         EXPECT_NE(EGL_NO_SURFACE, *pbuffer);
155     }
156 
bindIOSurfaceToTexture(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,EGLSurface * pbuffer,GLTexture * texture) const157     void bindIOSurfaceToTexture(const ScopedIOSurfaceRef &ioSurface,
158                                 EGLint width,
159                                 EGLint height,
160                                 EGLint plane,
161                                 GLenum internalFormat,
162                                 GLenum type,
163                                 EGLSurface *pbuffer,
164                                 GLTexture *texture) const
165     {
166         createIOSurfacePbuffer(ioSurface, width, height, plane, internalFormat, type, pbuffer);
167 
168         // Bind the pbuffer
169         glBindTexture(getGLTextureTarget(), *texture);
170         EGLBoolean result = eglBindTexImage(mDisplay, *pbuffer, EGL_BACK_BUFFER);
171         EXPECT_EGL_TRUE(result);
172         EXPECT_EGL_SUCCESS();
173     }
174 
doClearTest(const ScopedIOSurfaceRef & ioSurface,GLenum internalFormat,GLenum type,void * data,size_t dataSize)175     void doClearTest(const ScopedIOSurfaceRef &ioSurface,
176                      GLenum internalFormat,
177                      GLenum type,
178                      void *data,
179                      size_t dataSize)
180     {
181         // Bind the IOSurface to a texture and clear it.
182         EGLSurface pbuffer;
183         GLTexture texture;
184         bindIOSurfaceToTexture(ioSurface, 1, 1, 0, internalFormat, type, &pbuffer, &texture);
185 
186         GLFramebuffer fbo;
187         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
188         EXPECT_GL_NO_ERROR();
189         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(), texture,
190                                0);
191         EXPECT_GL_NO_ERROR();
192         EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
193         EXPECT_GL_NO_ERROR();
194 
195         glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
196         EXPECT_GL_NO_ERROR();
197         glClear(GL_COLOR_BUFFER_BIT);
198         EXPECT_GL_NO_ERROR();
199 
200         // Unbind pbuffer and check content.
201         EGLBoolean result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
202         EXPECT_EGL_TRUE(result);
203         EXPECT_EGL_SUCCESS();
204 
205         IOSurfaceLock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
206         ASSERT_EQ(0, memcmp(IOSurfaceGetBaseAddress(ioSurface.get()), data, dataSize));
207         IOSurfaceUnlock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
208 
209         result = eglDestroySurface(mDisplay, pbuffer);
210         EXPECT_EGL_TRUE(result);
211         EXPECT_EGL_SUCCESS();
212     }
213 
214     enum ColorMask
215     {
216         R = 1,
217         G = 2,
218         B = 4,
219         A = 8,
220     };
doSampleTest(const ScopedIOSurfaceRef & ioSurface,GLenum internalFormat,GLenum type,void * data,size_t dataSize,int mask)221     void doSampleTest(const ScopedIOSurfaceRef &ioSurface,
222                       GLenum internalFormat,
223                       GLenum type,
224                       void *data,
225                       size_t dataSize,
226                       int mask)
227     {
228         // Write the data to the IOSurface
229         IOSurfaceLock(ioSurface.get(), 0, nullptr);
230         memcpy(IOSurfaceGetBaseAddress(ioSurface.get()), data, dataSize);
231         IOSurfaceUnlock(ioSurface.get(), 0, nullptr);
232 
233         // Bind the IOSurface to a texture and clear it.
234         EGLSurface pbuffer;
235         GLTexture texture;
236         bindIOSurfaceToTexture(ioSurface, 1, 1, 0, internalFormat, type, &pbuffer, &texture);
237 
238         constexpr char kVS[] =
239             "attribute vec4 position;\n"
240             "void main()\n"
241             "{\n"
242             "    gl_Position = vec4(position.xy, 0.0, 1.0);\n"
243             "}\n";
244         constexpr char kFS_rect[] =
245             "#extension GL_ARB_texture_rectangle : require\n"
246             "precision mediump float;\n"
247             "uniform sampler2DRect tex;\n"
248             "void main()\n"
249             "{\n"
250             "    gl_FragColor = texture2DRect(tex, vec2(0, 0));\n"
251             "}\n";
252         constexpr char kFS_2D[] =
253             "precision mediump float;\n"
254             "uniform sampler2D tex;\n"
255             "void main()\n"
256             "{\n"
257             "    gl_FragColor = texture2D(tex, vec2(0, 0));\n"
258             "}\n";
259 
260         ANGLE_GL_PROGRAM(program, kVS,
261                          (getTextureTarget() == EGL_TEXTURE_RECTANGLE_ANGLE ? kFS_rect : kFS_2D));
262         glUseProgram(program);
263 
264         GLint location = glGetUniformLocation(program, "tex");
265         ASSERT_NE(-1, location);
266         glUniform1i(location, 0);
267 
268         glClearColor(0.0, 0.0, 0.0, 0.0);
269         glClear(GL_COLOR_BUFFER_BIT);
270         drawQuad(program, "position", 0.5f, 1.0f, false);
271 
272         GLColor expectedColor((mask & R) ? 1 : 0, (mask & G) ? 2 : 0, (mask & B) ? 3 : 0,
273                               (mask & A) ? 4 : 255);
274         EXPECT_PIXEL_COLOR_EQ(0, 0, expectedColor);
275         ASSERT_GL_NO_ERROR();
276     }
277 
doBlitTest(bool ioSurfaceIsSource,int width,int height)278     void doBlitTest(bool ioSurfaceIsSource, int width, int height)
279     {
280         // Create IOSurface and bind it to a texture.
281         ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(width, height, 'BGRA', 4);
282         EGLSurface pbuffer;
283         GLTexture texture;
284         bindIOSurfaceToTexture(ioSurface, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &pbuffer,
285                                &texture);
286 
287         GLFramebuffer iosurfaceFbo;
288         glBindFramebuffer(GL_FRAMEBUFFER, iosurfaceFbo);
289         EXPECT_GL_NO_ERROR();
290         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(), texture,
291                                0);
292         EXPECT_GL_NO_ERROR();
293         EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
294         EXPECT_GL_NO_ERROR();
295 
296         // Create another framebuffer with a regular renderbuffer.
297         GLFramebuffer fbo;
298         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
299         EXPECT_GL_NO_ERROR();
300         GLRenderbuffer rbo;
301         glBindRenderbuffer(GL_RENDERBUFFER, rbo);
302         EXPECT_GL_NO_ERROR();
303         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
304         EXPECT_GL_NO_ERROR();
305         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
306         EXPECT_GL_NO_ERROR();
307         EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
308         EXPECT_GL_NO_ERROR();
309 
310         glBindRenderbuffer(GL_RENDERBUFFER, 0);
311         EXPECT_GL_NO_ERROR();
312         glBindFramebuffer(GL_FRAMEBUFFER, 0);
313         EXPECT_GL_NO_ERROR();
314 
315         // Choose which is going to be the source and destination.
316         GLFramebuffer &src = ioSurfaceIsSource ? iosurfaceFbo : fbo;
317         GLFramebuffer &dst = ioSurfaceIsSource ? fbo : iosurfaceFbo;
318 
319         // Clear source to known color.
320         glBindFramebuffer(GL_FRAMEBUFFER, src);
321         glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
322         EXPECT_GL_NO_ERROR();
323         glClear(GL_COLOR_BUFFER_BIT);
324         EXPECT_GL_NO_ERROR();
325 
326         // Blit to destination.
327         glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, dst);
328         glBlitFramebufferANGLE(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
329                                GL_NEAREST);
330 
331         // Read back from destination.
332         glBindFramebuffer(GL_FRAMEBUFFER, dst);
333         GLColor expectedColor(1, 2, 3, 4);
334         EXPECT_PIXEL_COLOR_EQ(0, 0, expectedColor);
335 
336         // Unbind pbuffer and check content.
337         EGLBoolean result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
338         EXPECT_EGL_TRUE(result);
339         EXPECT_EGL_SUCCESS();
340 
341         result = eglDestroySurface(mDisplay, pbuffer);
342         EXPECT_EGL_TRUE(result);
343         EXPECT_EGL_SUCCESS();
344     }
345 
hasIOSurfaceExt() const346     bool hasIOSurfaceExt() const { return IsEGLDisplayExtensionEnabled(mDisplay, kIOSurfaceExt); }
347 
348     EGLConfig mConfig;
349     EGLDisplay mDisplay;
350 };
351 
352 // Test using BGRA8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToBGRA8888IOSurface)353 TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
354 {
355     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
356 
357     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
358 
359     GLColor color(3, 2, 1, 4);
360     doClearTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color));
361 }
362 
363 // Test reading from BGRA8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromBGRA8888IOSurface)364 TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA8888IOSurface)
365 {
366     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
367 
368     // TODO(http://anglebug.com/4369)
369     ANGLE_SKIP_TEST_IF(isSwiftshader());
370 
371     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
372 
373     GLColor color(3, 2, 1, 4);
374     doSampleTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B | A);
375 }
376 
377 // Test using BGRX8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToBGRX8888IOSurface)378 TEST_P(IOSurfaceClientBufferTest, RenderToBGRX8888IOSurface)
379 {
380     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
381 
382     // TODO(http://anglebug.com/4369)
383     ANGLE_SKIP_TEST_IF(isSwiftshader());
384 
385     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
386 
387     GLColor color(3, 2, 1, 255);
388     doClearTest(ioSurface, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color));
389 }
390 
391 // Test reading from BGRX8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromBGRX8888IOSurface)392 TEST_P(IOSurfaceClientBufferTest, ReadFromBGRX8888IOSurface)
393 {
394     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
395 
396     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
397 
398     GLColor color(3, 2, 1, 4);
399     doSampleTest(ioSurface, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B);
400 }
401 
402 // Test using RG88 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToRG88IOSurface)403 TEST_P(IOSurfaceClientBufferTest, RenderToRG88IOSurface)
404 {
405     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
406 
407     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
408 
409     uint8_t color[2] = {1, 2};
410     doClearTest(ioSurface, GL_RG, GL_UNSIGNED_BYTE, &color, sizeof(color));
411 }
412 
413 // Test reading from RG88 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromRG88IOSurface)414 TEST_P(IOSurfaceClientBufferTest, ReadFromRG88IOSurface)
415 {
416     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
417 
418     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
419 
420     uint8_t color[2] = {1, 2};
421     doSampleTest(ioSurface, GL_RG, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G);
422 }
423 
424 // Test using R8 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToR8IOSurface)425 TEST_P(IOSurfaceClientBufferTest, RenderToR8IOSurface)
426 {
427     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
428 
429     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
430 
431     uint8_t color = 1;
432     doClearTest(ioSurface, GL_RED, GL_UNSIGNED_BYTE, &color, sizeof(color));
433 }
434 
435 // Test reading from R8 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromR8IOSurface)436 TEST_P(IOSurfaceClientBufferTest, ReadFromR8IOSurface)
437 {
438     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
439 
440     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
441 
442     uint8_t color = 1;
443     doSampleTest(ioSurface, GL_RED, GL_UNSIGNED_BYTE, &color, sizeof(color), R);
444 }
445 
446 // Test using R16 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToR16IOSurface)447 TEST_P(IOSurfaceClientBufferTest, RenderToR16IOSurface)
448 {
449     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
450 
451     // This test only works on ES3.
452     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
453     // TODO(http://anglebug.com/4369)
454     ANGLE_SKIP_TEST_IF(isSwiftshader());
455 
456     // HACK(cwallez@chromium.org) 'L016' doesn't seem to be an official pixel format but it works
457     // sooooooo let's test using it
458     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L016', 2);
459 
460     uint16_t color = 257;
461     doClearTest(ioSurface, GL_R16UI, GL_UNSIGNED_SHORT, &color, sizeof(color));
462 }
463 // TODO(cwallez@chromium.org): test reading from R16? It returns 0 maybe because samplerRect is
464 // only for floating textures?
465 
466 // TODO(cwallez@chromium.org): Test using RGBA half float IOSurfaces ('RGhA')
467 
468 // Test blitting from IOSurface
TEST_P(IOSurfaceClientBufferTest,BlitFromIOSurface)469 TEST_P(IOSurfaceClientBufferTest, BlitFromIOSurface)
470 {
471     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
472 
473     doBlitTest(true, 2, 2);
474 }
475 
476 // Test blitting to IOSurface
TEST_P(IOSurfaceClientBufferTest,BlitToIOSurface)477 TEST_P(IOSurfaceClientBufferTest, BlitToIOSurface)
478 {
479     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
480 
481     doBlitTest(false, 2, 2);
482 }
483 
484 // Test the validation errors for missing attributes for eglCreatePbufferFromClientBuffer with
485 // IOSurface
TEST_P(IOSurfaceClientBufferTest,NegativeValidationMissingAttributes)486 TEST_P(IOSurfaceClientBufferTest, NegativeValidationMissingAttributes)
487 {
488     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
489 
490     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
491 
492     // Success case
493     {
494         // clang-format off
495         const EGLint attribs[] = {
496             EGL_WIDTH,                         10,
497             EGL_HEIGHT,                        10,
498             EGL_IOSURFACE_PLANE_ANGLE,         0,
499             EGL_TEXTURE_TARGET,                getTextureTarget(),
500             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
501             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
502             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
503             EGL_NONE,                          EGL_NONE,
504         };
505         // clang-format off
506 
507         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(), mConfig, attribs);
508         EXPECT_NE(EGL_NO_SURFACE, pbuffer);
509 
510         EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
511         EXPECT_EGL_TRUE(result);
512         EXPECT_EGL_SUCCESS();
513     }
514 
515     // Missing EGL_WIDTH
516     {
517         // clang-format off
518         const EGLint attribs[] = {
519             EGL_HEIGHT,                        10,
520             EGL_IOSURFACE_PLANE_ANGLE,         0,
521             EGL_TEXTURE_TARGET,                getTextureTarget(),
522             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
523             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
524             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
525             EGL_NONE,                          EGL_NONE,
526         };
527         // clang-format on
528 
529         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
530                                                               ioSurface.get(), mConfig, attribs);
531         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
532         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
533     }
534 
535     // Missing EGL_HEIGHT
536     {
537         // clang-format off
538         const EGLint attribs[] = {
539             EGL_WIDTH,                         10,
540             EGL_IOSURFACE_PLANE_ANGLE,         0,
541             EGL_TEXTURE_TARGET,                getTextureTarget(),
542             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
543             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
544             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
545             EGL_NONE,                          EGL_NONE,
546         };
547         // clang-format on
548 
549         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
550                                                               ioSurface.get(), mConfig, attribs);
551         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
552         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
553     }
554 
555     // Missing EGL_IOSURFACE_PLANE_ANGLE
556     {
557         // clang-format off
558         const EGLint attribs[] = {
559             EGL_WIDTH,                         10,
560             EGL_HEIGHT,                        10,
561             EGL_TEXTURE_TARGET,                getTextureTarget(),
562             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
563             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
564             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
565             EGL_NONE,                          EGL_NONE,
566         };
567         // clang-format on
568 
569         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
570                                                               ioSurface.get(), mConfig, attribs);
571         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
572         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
573     }
574 
575     // Missing EGL_TEXTURE_TARGET - EGL_BAD_MATCH from the base spec of
576     // eglCreatePbufferFromClientBuffer
577     {
578         // clang-format off
579         const EGLint attribs[] = {
580             EGL_WIDTH,                         10,
581             EGL_HEIGHT,                        10,
582             EGL_IOSURFACE_PLANE_ANGLE,         0,
583             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
584             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
585             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
586             EGL_NONE,                          EGL_NONE,
587         };
588         // clang-format on
589 
590         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
591                                                               ioSurface.get(), mConfig, attribs);
592         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
593         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
594     }
595 
596     // Missing EGL_TEXTURE_INTERNAL_FORMAT_ANGLE
597     {
598         // clang-format off
599         const EGLint attribs[] = {
600             EGL_WIDTH,                         10,
601             EGL_HEIGHT,                        10,
602             EGL_IOSURFACE_PLANE_ANGLE,         0,
603             EGL_TEXTURE_TARGET,                getTextureTarget(),
604             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
605             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
606             EGL_NONE,                          EGL_NONE,
607         };
608         // clang-format on
609 
610         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
611                                                               ioSurface.get(), mConfig, attribs);
612         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
613         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
614     }
615 
616     // Missing EGL_TEXTURE_FORMAT - EGL_BAD_MATCH from the base spec of
617     // eglCreatePbufferFromClientBuffer
618     {
619         // clang-format off
620         const EGLint attribs[] = {
621             EGL_WIDTH,                         10,
622             EGL_HEIGHT,                        10,
623             EGL_IOSURFACE_PLANE_ANGLE,         0,
624             EGL_TEXTURE_TARGET,                getTextureTarget(),
625             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
626             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
627             EGL_NONE,                          EGL_NONE,
628         };
629         // clang-format on
630 
631         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
632                                                               ioSurface.get(), mConfig, attribs);
633         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
634         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
635     }
636 
637     // Missing EGL_TEXTURE_TYPE_ANGLE
638     {
639         // clang-format off
640         const EGLint attribs[] = {
641             EGL_WIDTH,                         10,
642             EGL_HEIGHT,                        10,
643             EGL_IOSURFACE_PLANE_ANGLE,         0,
644             EGL_TEXTURE_TARGET,                getTextureTarget(),
645             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
646             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
647             EGL_NONE,                          EGL_NONE,
648         };
649         // clang-format on
650 
651         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
652                                                               ioSurface.get(), mConfig, attribs);
653         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
654         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
655     }
656 }
657 
658 // Test the validation errors for bad parameters for eglCreatePbufferFromClientBuffer with IOSurface
TEST_P(IOSurfaceClientBufferTest,NegativeValidationBadAttributes)659 TEST_P(IOSurfaceClientBufferTest, NegativeValidationBadAttributes)
660 {
661     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
662 
663     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
664 
665     // Success case
666     {
667         // clang-format off
668         const EGLint attribs[] = {
669             EGL_WIDTH,                         10,
670             EGL_HEIGHT,                        10,
671             EGL_IOSURFACE_PLANE_ANGLE,         0,
672             EGL_TEXTURE_TARGET,                getTextureTarget(),
673             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
674             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
675             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
676             EGL_NONE,                          EGL_NONE,
677         };
678         // clang-format off
679 
680         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(), mConfig, attribs);
681         EXPECT_NE(EGL_NO_SURFACE, pbuffer);
682 
683         EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
684         EXPECT_EGL_TRUE(result);
685         EXPECT_EGL_SUCCESS();
686     }
687 
688     // EGL_TEXTURE_FORMAT must be EGL_TEXTURE_RGBA
689     {
690         // clang-format off
691         const EGLint attribs[] = {
692             EGL_WIDTH,                         10,
693             EGL_HEIGHT,                        10,
694             EGL_IOSURFACE_PLANE_ANGLE,         0,
695             EGL_TEXTURE_TARGET,                getTextureTarget(),
696             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
697             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGB,
698             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
699             EGL_NONE,                          EGL_NONE,
700         };
701         // clang-format on
702 
703         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
704                                                               ioSurface.get(), mConfig, attribs);
705         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
706         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
707     }
708 
709     // EGL_WIDTH must be at least 1
710     {
711         // clang-format off
712         const EGLint attribs[] = {
713             EGL_WIDTH,                         0,
714             EGL_HEIGHT,                        10,
715             EGL_IOSURFACE_PLANE_ANGLE,         0,
716             EGL_TEXTURE_TARGET,                getTextureTarget(),
717             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
718             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
719             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
720             EGL_NONE,                          EGL_NONE,
721         };
722         // clang-format on
723 
724         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
725                                                               ioSurface.get(), mConfig, attribs);
726         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
727         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
728     }
729 
730     // EGL_WIDTH must be at most the width of the IOSurface
731     {
732         // clang-format off
733         const EGLint attribs[] = {
734             EGL_WIDTH,                         11,
735             EGL_HEIGHT,                        10,
736             EGL_IOSURFACE_PLANE_ANGLE,         0,
737             EGL_TEXTURE_TARGET,                getTextureTarget(),
738             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
739             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
740             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
741             EGL_NONE,                          EGL_NONE,
742         };
743         // clang-format on
744 
745         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
746                                                               ioSurface.get(), mConfig, attribs);
747         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
748         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
749     }
750 
751     // EGL_HEIGHT must be at least 1
752     {
753         // clang-format off
754         const EGLint attribs[] = {
755             EGL_WIDTH,                         10,
756             EGL_HEIGHT,                        0,
757             EGL_IOSURFACE_PLANE_ANGLE,         0,
758             EGL_TEXTURE_TARGET,                getTextureTarget(),
759             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
760             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
761             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
762             EGL_NONE,                          EGL_NONE,
763         };
764         // clang-format on
765 
766         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
767                                                               ioSurface.get(), mConfig, attribs);
768         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
769         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
770     }
771 
772     // EGL_HEIGHT must be at most the height of the IOSurface
773     {
774         // clang-format off
775         const EGLint attribs[] = {
776             EGL_WIDTH,                         10,
777             EGL_HEIGHT,                        11,
778             EGL_IOSURFACE_PLANE_ANGLE,         0,
779             EGL_TEXTURE_TARGET,                getTextureTarget(),
780             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
781             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
782             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
783             EGL_NONE,                          EGL_NONE,
784         };
785         // clang-format on
786 
787         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
788                                                               ioSurface.get(), mConfig, attribs);
789         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
790         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
791     }
792 
793     // EGL_TEXTURE_FORMAT must be equal to the config's texture target
794     {
795         EGLint target      = getTextureTarget();
796         EGLint wrongTarget = 0;
797         switch (target)
798         {
799             case EGL_TEXTURE_RECTANGLE_ANGLE:
800                 wrongTarget = EGL_TEXTURE_2D;
801                 break;
802             case EGL_TEXTURE_2D:
803                 wrongTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
804                 break;
805             default:
806                 break;
807         }
808         // clang-format off
809         const EGLint attribs[] = {
810             EGL_WIDTH,                         10,
811             EGL_HEIGHT,                        10,
812             EGL_IOSURFACE_PLANE_ANGLE,         0,
813             EGL_TEXTURE_TARGET,                wrongTarget,
814             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
815             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
816             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
817             EGL_NONE,                          EGL_NONE,
818         };
819         // clang-format on
820 
821         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
822                                                               ioSurface.get(), mConfig, attribs);
823         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
824         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
825     }
826 
827     // EGL_IOSURFACE_PLANE_ANGLE must be at least 0
828     {
829         // clang-format off
830         const EGLint attribs[] = {
831             EGL_WIDTH,                         10,
832             EGL_HEIGHT,                        10,
833             EGL_IOSURFACE_PLANE_ANGLE,         -1,
834             EGL_TEXTURE_TARGET,                getTextureTarget(),
835             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
836             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
837             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
838             EGL_NONE,                          EGL_NONE,
839         };
840         // clang-format on
841 
842         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
843                                                               ioSurface.get(), mConfig, attribs);
844         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
845         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
846     }
847 
848     // EGL_IOSURFACE_PLANE_ANGLE must less than the number of planes of the IOSurface
849     {
850         // clang-format off
851         const EGLint attribs[] = {
852             EGL_WIDTH,                         10,
853             EGL_HEIGHT,                        10,
854             EGL_IOSURFACE_PLANE_ANGLE,         1,
855             EGL_TEXTURE_TARGET,                getTextureTarget(),
856             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
857             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
858             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
859             EGL_NONE,                          EGL_NONE,
860         };
861         // clang-format on
862 
863         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
864                                                               ioSurface.get(), mConfig, attribs);
865         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
866         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
867     }
868 
869     // The internal format / type most be listed in the table
870     {
871         // clang-format off
872         const EGLint attribs[] = {
873             EGL_WIDTH,                         10,
874             EGL_HEIGHT,                        10,
875             EGL_IOSURFACE_PLANE_ANGLE,         0,
876             EGL_TEXTURE_TARGET,                getTextureTarget(),
877             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGBA,
878             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
879             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
880             EGL_NONE,                          EGL_NONE,
881         };
882         // clang-format on
883 
884         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
885                                                               ioSurface.get(), mConfig, attribs);
886         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
887         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
888     }
889 }
890 
891 // Test IOSurface pbuffers can be made current
TEST_P(IOSurfaceClientBufferTest,MakeCurrent)892 TEST_P(IOSurfaceClientBufferTest, MakeCurrent)
893 {
894     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
895 
896     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
897 
898     EGLSurface pbuffer;
899     createIOSurfacePbuffer(ioSurface, 10, 10, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &pbuffer);
900 
901     EGLContext context = getEGLWindow()->getContext();
902     EGLBoolean result  = eglMakeCurrent(mDisplay, pbuffer, pbuffer, context);
903     EXPECT_EGL_TRUE(result);
904     EXPECT_EGL_SUCCESS();
905     // The test harness expects the EGL state to be restored before the test exits.
906     result = eglMakeCurrent(mDisplay, getEGLWindow()->getSurface(), getEGLWindow()->getSurface(),
907                             context);
908     EXPECT_EGL_TRUE(result);
909     EXPECT_EGL_SUCCESS();
910 }
911 
912 // TODO(cwallez@chromium.org): Test setting width and height to less than the IOSurface's work as
913 // expected.
914 
915 ANGLE_INSTANTIATE_TEST(IOSurfaceClientBufferTest,
916                        ES2_OPENGL(),
917                        ES3_OPENGL(),
918                        ES2_VULKAN_SWIFTSHADER(),
919                        ES3_VULKAN_SWIFTSHADER());
920