xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLIOSurfaceClientBufferTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 #if TARGET_OS_OSX
17 #    include <IOSurface/IOSurface.h>
18 #else
19 #    include <IOSurface/IOSurfaceRef.h>
20 #endif
21 using namespace angle;
22 
23 namespace
24 {
25 
26 constexpr char kIOSurfaceExt[] = "EGL_ANGLE_iosurface_client_buffer";
27 
AddIntegerValue(CFMutableDictionaryRef dictionary,const CFStringRef key,int32_t value)28 void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, int32_t value)
29 {
30     CFNumberRef number = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value);
31     CFDictionaryAddValue(dictionary, key, number);
32     CFRelease(number);
33 }
34 
35 class [[nodiscard]] ScopedIOSurfaceRef : angle::NonCopyable
36 {
37   public:
ScopedIOSurfaceRef(IOSurfaceRef surface)38     explicit ScopedIOSurfaceRef(IOSurfaceRef surface) : mSurface(surface) {}
39 
~ScopedIOSurfaceRef()40     ~ScopedIOSurfaceRef()
41     {
42         if (mSurface != nullptr)
43         {
44             CFRelease(mSurface);
45             mSurface = nullptr;
46         }
47     }
48 
get() const49     IOSurfaceRef get() const { return mSurface; }
50 
ScopedIOSurfaceRef(ScopedIOSurfaceRef && other)51     ScopedIOSurfaceRef(ScopedIOSurfaceRef &&other)
52     {
53         if (mSurface != nullptr)
54         {
55             CFRelease(mSurface);
56         }
57         mSurface       = other.mSurface;
58         other.mSurface = nullptr;
59     }
60 
operator =(ScopedIOSurfaceRef && other)61     ScopedIOSurfaceRef &operator=(ScopedIOSurfaceRef &&other)
62     {
63         if (mSurface != nullptr)
64         {
65             CFRelease(mSurface);
66         }
67         mSurface       = other.mSurface;
68         other.mSurface = nullptr;
69 
70         return *this;
71     }
72 
73   private:
74     IOSurfaceRef mSurface = nullptr;
75 };
76 
77 struct IOSurfacePlaneInfo
78 {
79     int width;
80     int height;
81     int bytesPerElement;
82 };
83 
CreateIOSurface(int32_t format,const std::vector<IOSurfacePlaneInfo> & planes)84 ScopedIOSurfaceRef CreateIOSurface(int32_t format, const std::vector<IOSurfacePlaneInfo> &planes)
85 {
86     EXPECT_GT(planes.size(), 0u);
87 
88     CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
89         kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
90     AddIntegerValue(dict, kIOSurfaceWidth, planes[0].width);
91     AddIntegerValue(dict, kIOSurfaceHeight, planes[0].height);
92     AddIntegerValue(dict, kIOSurfacePixelFormat, format);
93 
94     if (planes.size() > 1)
95     {
96         CFMutableArrayRef planesInfo =
97             CFArrayCreateMutable(kCFAllocatorDefault, planes.size(), &kCFTypeArrayCallBacks);
98         for (const IOSurfacePlaneInfo &plane : planes)
99         {
100             CFMutableDictionaryRef planeInfo =
101                 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
102                                           &kCFTypeDictionaryValueCallBacks);
103             AddIntegerValue(planeInfo, kIOSurfacePlaneWidth, plane.width);
104             AddIntegerValue(planeInfo, kIOSurfacePlaneHeight, plane.height);
105             AddIntegerValue(planeInfo, kIOSurfacePlaneBytesPerElement, plane.bytesPerElement);
106 
107             CFArrayAppendValue(planesInfo, planeInfo);
108             CFRelease(planeInfo);
109         }
110 
111         CFDictionaryAddValue(dict, kIOSurfacePlaneInfo, planesInfo);
112         CFRelease(planesInfo);
113     }
114     else
115     {
116         AddIntegerValue(dict, kIOSurfaceBytesPerElement, planes[0].bytesPerElement);
117     }
118 
119     IOSurfaceRef ioSurface = IOSurfaceCreate(dict);
120     EXPECT_NE(nullptr, ioSurface);
121     CFRelease(dict);
122 
123     return ScopedIOSurfaceRef(ioSurface);
124 }
125 
CreateSinglePlaneIOSurface(int width,int height,int32_t format,int bytesPerElement)126 ScopedIOSurfaceRef CreateSinglePlaneIOSurface(int width,
127                                               int height,
128                                               int32_t format,
129                                               int bytesPerElement)
130 {
131     std::vector<IOSurfacePlaneInfo> planes{{width, height, bytesPerElement}};
132     return CreateIOSurface(format, planes);
133 }
134 
135 }  // anonymous namespace
136 
137 class IOSurfaceClientBufferTest : public ANGLETest<>
138 {
139   protected:
getTextureTarget() const140     EGLint getTextureTarget() const
141     {
142         EGLint target = 0;
143         eglGetConfigAttrib(mDisplay, mConfig, EGL_BIND_TO_TEXTURE_TARGET_ANGLE, &target);
144         return target;
145     }
146 
getGLTextureTarget() const147     GLint getGLTextureTarget() const
148     {
149         EGLint targetEGL = getTextureTarget();
150         GLenum targetGL  = 0;
151         switch (targetEGL)
152         {
153             case EGL_TEXTURE_2D:
154                 targetGL = GL_TEXTURE_2D;
155                 break;
156             case EGL_TEXTURE_RECTANGLE_ANGLE:
157                 targetGL = GL_TEXTURE_RECTANGLE_ANGLE;
158                 break;
159             default:
160                 break;
161         }
162         return targetGL;
163     }
164 
IOSurfaceClientBufferTest()165     IOSurfaceClientBufferTest() : mConfig(0), mDisplay(nullptr) {}
166 
testSetUp()167     void testSetUp() override
168     {
169         mConfig  = getEGLWindow()->getConfig();
170         mDisplay = getEGLWindow()->getDisplay();
171     }
172 
createIOSurfacePbuffer(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,EGLSurface * pbuffer) const173     void createIOSurfacePbuffer(const ScopedIOSurfaceRef &ioSurface,
174                                 EGLint width,
175                                 EGLint height,
176                                 EGLint plane,
177                                 GLenum internalFormat,
178                                 GLenum type,
179                                 EGLSurface *pbuffer) const
180     {
181         // clang-format off
182         const EGLint attribs[] = {
183             EGL_WIDTH,                         width,
184             EGL_HEIGHT,                        height,
185             EGL_IOSURFACE_PLANE_ANGLE,         plane,
186             EGL_TEXTURE_TARGET,                getTextureTarget(),
187             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE,
188                 static_cast<EGLint>(internalFormat),
189             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
190             EGL_TEXTURE_TYPE_ANGLE,            static_cast<EGLint>(type),
191             EGL_NONE,                          EGL_NONE,
192         };
193         // clang-format on
194 
195         *pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(),
196                                                     mConfig, attribs);
197         EXPECT_NE(EGL_NO_SURFACE, *pbuffer);
198     }
199 
bindIOSurfaceToTexture(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,EGLSurface * pbuffer,GLTexture * texture) const200     void bindIOSurfaceToTexture(const ScopedIOSurfaceRef &ioSurface,
201                                 EGLint width,
202                                 EGLint height,
203                                 EGLint plane,
204                                 GLenum internalFormat,
205                                 GLenum type,
206                                 EGLSurface *pbuffer,
207                                 GLTexture *texture) const
208     {
209         createIOSurfacePbuffer(ioSurface, width, height, plane, internalFormat, type, pbuffer);
210 
211         // Bind the pbuffer
212         glBindTexture(getGLTextureTarget(), *texture);
213         EGLBoolean result = eglBindTexImage(mDisplay, *pbuffer, EGL_BACK_BUFFER);
214         EXPECT_EGL_TRUE(result);
215         EXPECT_EGL_SUCCESS();
216     }
217 
doClearTest(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,const GLColor & data)218     void doClearTest(const ScopedIOSurfaceRef &ioSurface,
219                      EGLint width,
220                      EGLint height,
221                      EGLint plane,
222                      GLenum internalFormat,
223                      GLenum type,
224                      const GLColor &data)
225     {
226         std::array<uint8_t, 4> dataArray{data.R, data.G, data.B, data.A};
227         doClearTest(ioSurface, width, height, plane, internalFormat, type, dataArray);
228     }
229 
230     template <typename T, size_t dataSize>
doClearTest(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,const std::array<T,dataSize> & data)231     void doClearTest(const ScopedIOSurfaceRef &ioSurface,
232                      EGLint width,
233                      EGLint height,
234                      EGLint plane,
235                      GLenum internalFormat,
236                      GLenum type,
237                      const std::array<T, dataSize> &data)
238     {
239         // Bind the IOSurface to a texture and clear it.
240         EGLSurface pbuffer;
241         GLTexture texture;
242         bindIOSurfaceToTexture(ioSurface, width, height, plane, internalFormat, type, &pbuffer,
243                                &texture);
244 
245         GLFramebuffer fbo;
246         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
247         EXPECT_GL_NO_ERROR();
248         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(), texture,
249                                0);
250         EXPECT_GL_NO_ERROR();
251         ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
252         EXPECT_GL_NO_ERROR();
253 
254         glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
255         EXPECT_GL_NO_ERROR();
256         glClear(GL_COLOR_BUFFER_BIT);
257         EXPECT_GL_NO_ERROR();
258 
259         // Unbind pbuffer and check content.
260         EGLBoolean result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
261         EXPECT_EGL_TRUE(result);
262         EXPECT_EGL_SUCCESS();
263 
264         // IOSurface client buffer's rendering doesn't automatically finish after
265         // eglReleaseTexImage(). Need to explicitly call glFinish().
266         glFinish();
267 
268         IOSurfaceLock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
269         std::array<T, dataSize> iosurfaceData;
270         memcpy(iosurfaceData.data(), IOSurfaceGetBaseAddressOfPlane(ioSurface.get(), plane),
271                sizeof(T) * data.size());
272         IOSurfaceUnlock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
273 
274         if (internalFormat == GL_RGB && IsMac() && IsOpenGL())
275         {
276             // Ignore alpha component for BGRX, the alpha value is undefined
277             for (int i = 0; i < 3; i++)
278             {
279                 ASSERT_EQ(data[i], iosurfaceData[i]);
280             }
281         }
282         else
283         {
284             ASSERT_EQ(data, iosurfaceData);
285         }
286 
287         result = eglDestroySurface(mDisplay, pbuffer);
288         EXPECT_EGL_TRUE(result);
289         EXPECT_EGL_SUCCESS();
290     }
291 
292     enum ColorMask
293     {
294         R = 1,
295         G = 2,
296         B = 4,
297         A = 8,
298     };
doSampleTestWithExtraSteps(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,void * data,size_t dataSize,int mask,const std::function<void ()> & extraStepsBeforeSample)299     void doSampleTestWithExtraSteps(const ScopedIOSurfaceRef &ioSurface,
300                                     EGLint width,
301                                     EGLint height,
302                                     EGLint plane,
303                                     GLenum internalFormat,
304                                     GLenum type,
305                                     void *data,
306                                     size_t dataSize,
307                                     int mask,
308                                     const std::function<void()> &extraStepsBeforeSample)
309     {
310         // Write the data to the IOSurface
311         IOSurfaceLock(ioSurface.get(), 0, nullptr);
312         memcpy(IOSurfaceGetBaseAddressOfPlane(ioSurface.get(), plane), data, dataSize);
313         IOSurfaceUnlock(ioSurface.get(), 0, nullptr);
314 
315         GLTexture texture;
316         glBindTexture(getGLTextureTarget(), texture);
317         glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
318         glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
319 
320         // Bind the IOSurface to a texture and clear it.
321         EGLSurface pbuffer;
322         bindIOSurfaceToTexture(ioSurface, width, height, plane, internalFormat, type, &pbuffer,
323                                &texture);
324 
325         if (extraStepsBeforeSample)
326         {
327             extraStepsBeforeSample();
328         }
329 
330         doSampleTestWithTexture(texture, mask);
331 
332         EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
333         EXPECT_EGL_TRUE(result);
334         EXPECT_EGL_SUCCESS();
335     }
336 
doSampleTest(const ScopedIOSurfaceRef & ioSurface,EGLint width,EGLint height,EGLint plane,GLenum internalFormat,GLenum type,void * data,size_t dataSize,int mask)337     void doSampleTest(const ScopedIOSurfaceRef &ioSurface,
338                       EGLint width,
339                       EGLint height,
340                       EGLint plane,
341                       GLenum internalFormat,
342                       GLenum type,
343                       void *data,
344                       size_t dataSize,
345                       int mask)
346     {
347         doSampleTestWithExtraSteps(ioSurface, width, height, plane, internalFormat, type, data,
348                                    dataSize, mask, nullptr);
349     }
350 
doSampleTestWithTexture(const GLTexture & texture,int mask)351     void doSampleTestWithTexture(const GLTexture &texture, int mask)
352     {
353         constexpr char kVS[] =
354             "attribute vec4 position;\n"
355             "void main()\n"
356             "{\n"
357             "    gl_Position = vec4(position.xy, 0.0, 1.0);\n"
358             "}\n";
359         constexpr char kFS_rect[] =
360             "#extension GL_ARB_texture_rectangle : require\n"
361             "precision mediump float;\n"
362             "uniform sampler2DRect tex;\n"
363             "void main()\n"
364             "{\n"
365             "    gl_FragColor = texture2DRect(tex, vec2(0, 0));\n"
366             "}\n";
367         constexpr char kFS_2D[] =
368             "precision mediump float;\n"
369             "uniform sampler2D tex;\n"
370             "void main()\n"
371             "{\n"
372             "    gl_FragColor = texture2D(tex, vec2(0, 0));\n"
373             "}\n";
374 
375         ANGLE_GL_PROGRAM(program, kVS,
376                          (getTextureTarget() == EGL_TEXTURE_RECTANGLE_ANGLE ? kFS_rect : kFS_2D));
377         glUseProgram(program);
378 
379         GLint location = glGetUniformLocation(program, "tex");
380         ASSERT_NE(-1, location);
381         glUniform1i(location, 0);
382 
383         glClearColor(0.0, 0.0, 0.0, 0.0);
384         glClear(GL_COLOR_BUFFER_BIT);
385         drawQuad(program, "position", 0.5f, 1.0f, false);
386 
387         GLColor expectedColor((mask & R) ? 1 : 0, (mask & G) ? 2 : 0, (mask & B) ? 3 : 0,
388                               (mask & A) ? 4 : 255);
389         EXPECT_PIXEL_COLOR_EQ(0, 0, expectedColor);
390         ASSERT_GL_NO_ERROR();
391     }
392 
doBlitTest(bool ioSurfaceIsSource,int width,int height)393     void doBlitTest(bool ioSurfaceIsSource, int width, int height)
394     {
395         if (!hasBlitExt())
396         {
397             return;
398         }
399 
400         // Create IOSurface and bind it to a texture.
401         ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(width, height, 'BGRA', 4);
402         EGLSurface pbuffer;
403         GLTexture texture;
404         bindIOSurfaceToTexture(ioSurface, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &pbuffer,
405                                &texture);
406 
407         GLFramebuffer iosurfaceFbo;
408         glBindFramebuffer(GL_FRAMEBUFFER, iosurfaceFbo);
409         EXPECT_GL_NO_ERROR();
410         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(), texture,
411                                0);
412         EXPECT_GL_NO_ERROR();
413         ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
414         EXPECT_GL_NO_ERROR();
415 
416         // Create another framebuffer with a regular renderbuffer.
417         GLFramebuffer fbo;
418         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
419         EXPECT_GL_NO_ERROR();
420         GLRenderbuffer rbo;
421         glBindRenderbuffer(GL_RENDERBUFFER, rbo);
422         EXPECT_GL_NO_ERROR();
423         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
424         EXPECT_GL_NO_ERROR();
425         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
426         EXPECT_GL_NO_ERROR();
427         ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
428         EXPECT_GL_NO_ERROR();
429 
430         glBindRenderbuffer(GL_RENDERBUFFER, 0);
431         EXPECT_GL_NO_ERROR();
432         glBindFramebuffer(GL_FRAMEBUFFER, 0);
433         EXPECT_GL_NO_ERROR();
434 
435         // Choose which is going to be the source and destination.
436         GLFramebuffer &src = ioSurfaceIsSource ? iosurfaceFbo : fbo;
437         GLFramebuffer &dst = ioSurfaceIsSource ? fbo : iosurfaceFbo;
438 
439         // Clear source to known color.
440         glBindFramebuffer(GL_FRAMEBUFFER, src);
441         glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
442         EXPECT_GL_NO_ERROR();
443         glClear(GL_COLOR_BUFFER_BIT);
444         EXPECT_GL_NO_ERROR();
445 
446         // Blit to destination.
447         glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, dst);
448         glBlitFramebufferANGLE(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
449                                GL_NEAREST);
450 
451         // Read back from destination.
452         glBindFramebuffer(GL_FRAMEBUFFER, dst);
453         GLColor expectedColor(1, 2, 3, 4);
454         EXPECT_PIXEL_COLOR_EQ(0, 0, expectedColor);
455 
456         // Unbind pbuffer and check content.
457         EGLBoolean result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
458         EXPECT_EGL_TRUE(result);
459         EXPECT_EGL_SUCCESS();
460 
461         result = eglDestroySurface(mDisplay, pbuffer);
462         EXPECT_EGL_TRUE(result);
463         EXPECT_EGL_SUCCESS();
464     }
465 
hasIOSurfaceExt() const466     bool hasIOSurfaceExt() const { return IsEGLDisplayExtensionEnabled(mDisplay, kIOSurfaceExt); }
hasBlitExt() const467     bool hasBlitExt() const
468     {
469         return IsEGLDisplayExtensionEnabled(mDisplay, "ANGLE_framebuffer_blit");
470     }
471 
472     EGLConfig mConfig;
473     EGLDisplay mDisplay;
474 };
475 
476 // Test using RGBA8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToRGBA8888IOSurface)477 TEST_P(IOSurfaceClientBufferTest, RenderToRGBA8888IOSurface)
478 {
479     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
480 
481     // DesktopOpenGL doesn't support RGBA IOSurface.
482     ANGLE_SKIP_TEST_IF(IsDesktopOpenGL());
483 
484     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'RGBA', 4);
485 
486     GLColor color(1, 2, 3, 4);
487     doClearTest(ioSurface, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, color);
488 }
489 
490 // Test reading from RGBA8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromRGBA8888IOSurface)491 TEST_P(IOSurfaceClientBufferTest, ReadFromRGBA8888IOSurface)
492 {
493     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
494 
495     // DesktopOpenGL doesn't support RGBA IOSurface.
496     ANGLE_SKIP_TEST_IF(IsDesktopOpenGL());
497 
498     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'RGBA', 4);
499 
500     GLColor color(1, 2, 3, 4);
501     doSampleTest(ioSurface, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color, sizeof(color),
502                  R | G | B | A);
503 }
504 
505 // Test using BGRA8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToBGRA8888IOSurface)506 TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
507 {
508     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
509 
510     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
511 
512     GLColor color(3, 2, 1, 4);
513     doClearTest(ioSurface, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, color);
514 }
515 
516 // Test reading from BGRA8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromBGRA8888IOSurface)517 TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA8888IOSurface)
518 {
519     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
520 
521     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
522 
523     GLColor color(3, 2, 1, 4);
524     doSampleTest(ioSurface, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color),
525                  R | G | B | A);
526 }
527 
528 // Test using RGBX8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToRGBX8888IOSurface)529 TEST_P(IOSurfaceClientBufferTest, RenderToRGBX8888IOSurface)
530 {
531     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
532 
533     // DesktopOpenGL doesn't support RGBA IOSurface.
534     ANGLE_SKIP_TEST_IF(IsDesktopOpenGL());
535 
536     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'RGBA', 4);
537 
538     GLColor color(1, 2, 3, 255);
539     doClearTest(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, color);
540 }
541 
542 // Test reading from RGBX8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromRGBX8888IOSurface)543 TEST_P(IOSurfaceClientBufferTest, ReadFromRGBX8888IOSurface)
544 {
545     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
546 
547     // DesktopOpenGL doesn't support RGBA IOSurface.
548     ANGLE_SKIP_TEST_IF(IsDesktopOpenGL());
549 
550     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'RGBA', 4);
551 
552     GLColor color(1, 2, 3, 255);
553     doSampleTest(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B);
554 }
555 
556 // Test using BGRX8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToBGRX8888IOSurface)557 TEST_P(IOSurfaceClientBufferTest, RenderToBGRX8888IOSurface)
558 {
559     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
560 
561     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
562 
563     GLColor color(3, 2, 1, 255);
564     doClearTest(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, color);
565 }
566 
567 // Test reading from BGRX8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromBGRX8888IOSurface)568 TEST_P(IOSurfaceClientBufferTest, ReadFromBGRX8888IOSurface)
569 {
570     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
571 
572     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
573 
574     GLColor color(3, 2, 1, 4);
575     doSampleTest(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B);
576 }
577 
578 // Test using RG88 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToRG88IOSurface)579 TEST_P(IOSurfaceClientBufferTest, RenderToRG88IOSurface)
580 {
581     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
582 
583     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
584 
585     std::array<uint8_t, 2> color{1, 2};
586     doClearTest(ioSurface, 1, 1, 0, GL_RG, GL_UNSIGNED_BYTE, color);
587 }
588 
589 // Test reading from RG88 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromRG88IOSurface)590 TEST_P(IOSurfaceClientBufferTest, ReadFromRG88IOSurface)
591 {
592     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
593 
594     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
595 
596     uint8_t color[2] = {1, 2};
597     doSampleTest(ioSurface, 1, 1, 0, GL_RG, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G);
598 }
599 
600 // Test using R8 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToR8IOSurface)601 TEST_P(IOSurfaceClientBufferTest, RenderToR8IOSurface)
602 {
603     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
604 
605     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
606 
607     std::array<uint8_t, 1> color{1};
608     doClearTest(ioSurface, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, color);
609 }
610 
611 // Test reading from R8 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromR8IOSurface)612 TEST_P(IOSurfaceClientBufferTest, ReadFromR8IOSurface)
613 {
614     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
615 
616     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
617 
618     uint8_t color = 1;
619     doSampleTest(ioSurface, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &color, sizeof(color), R);
620 }
621 
622 // Test using RG1616 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToRG1616IOSurface)623 TEST_P(IOSurfaceClientBufferTest, RenderToRG1616IOSurface)
624 {
625     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
626     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_norm16"));
627 
628     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C16', 4);
629 
630     std::array<uint16_t, 2> color{257, 514};
631     doClearTest(ioSurface, 1, 1, 0, GL_RG, GL_UNSIGNED_SHORT, color);
632 }
633 
634 // Test reading from RG1616 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromRG1616IOSurface)635 TEST_P(IOSurfaceClientBufferTest, ReadFromRG1616IOSurface)
636 {
637     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
638     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_norm16"));
639 
640     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C16', 4);
641 
642     uint16_t color[2] = {257, 514};
643     doSampleTest(ioSurface, 1, 1, 0, GL_RG, GL_UNSIGNED_SHORT, &color, sizeof(color), R | G);
644 }
645 
646 // Test using R16 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToR16IOSurface)647 TEST_P(IOSurfaceClientBufferTest, RenderToR16IOSurface)
648 {
649     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
650     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_norm16"));
651 
652     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L016', 2);
653 
654     std::array<uint16_t, 1> color{257};
655     doClearTest(ioSurface, 1, 1, 0, GL_RED, GL_UNSIGNED_SHORT, color);
656 }
657 
658 // Test reading from R16 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromR16IOSurface)659 TEST_P(IOSurfaceClientBufferTest, ReadFromR16IOSurface)
660 {
661     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
662     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_norm16"));
663 
664     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L016', 2);
665 
666     uint16_t color = 257;
667     doSampleTest(ioSurface, 1, 1, 0, GL_RED, GL_UNSIGNED_SHORT, &color, sizeof(color), R);
668 }
669 
670 // Test using BGRA_1010102 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToBGRA1010102IOSurface)671 TEST_P(IOSurfaceClientBufferTest, RenderToBGRA1010102IOSurface)
672 {
673     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
674 
675     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'l10r', 4);
676 
677     std::array<uint32_t, 1> color{(0 << 30) | (1 << 22) | (2 << 12) | (3 << 2)};
678     doClearTest(ioSurface, 1, 1, 0, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, color);
679 }
680 
681 // Test reading from BGRA_1010102 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromBGRA1010102IOSurface)682 TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA1010102IOSurface)
683 {
684     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
685 
686     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'l10r', 4);
687 
688     uint32_t color = (3 << 30) | (1 << 22) | (2 << 12) | (3 << 2);
689     doSampleTest(ioSurface, 1, 1, 0, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, &color,
690                  sizeof(color),
691                  R | G | B);  // Don't test alpha, unorm '4' can't be represented with 2 bits.
692 }
693 
694 // Test using RGBA_16F IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToRGBA16FIOSurface)695 TEST_P(IOSurfaceClientBufferTest, RenderToRGBA16FIOSurface)
696 {
697     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
698 
699     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'RGhA', 8);
700 
701     std::array<GLushort, 4> color{
702         gl::float32ToFloat16(1.0f / 255.0f), gl::float32ToFloat16(2.0f / 255.0f),
703         gl::float32ToFloat16(3.0f / 255.0f), gl::float32ToFloat16(4.0f / 255.0f)};
704     doClearTest(ioSurface, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT, color);
705 }
706 
707 // Test reading from RGBA_16F IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromToRGBA16FIOSurface)708 TEST_P(IOSurfaceClientBufferTest, ReadFromToRGBA16FIOSurface)
709 {
710     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
711 
712     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'RGhA', 8);
713 
714     std::array<GLushort, 4> color{
715         gl::float32ToFloat16(1.0f / 255.0f), gl::float32ToFloat16(2.0f / 255.0f),
716         gl::float32ToFloat16(3.0f / 255.0f), gl::float32ToFloat16(4.0f / 255.0f)};
717     doSampleTest(ioSurface, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT, color.data(), sizeof(GLushort) * 4,
718                  R | G | B | A);
719 }
720 
721 // Test using YUV420 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToYUV420IOSurface)722 TEST_P(IOSurfaceClientBufferTest, RenderToYUV420IOSurface)
723 {
724     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
725 
726     std::vector<IOSurfacePlaneInfo> planes{{2, 2, 1}, {1, 1, 2}};
727     ScopedIOSurfaceRef ioSurface = CreateIOSurface('420v', planes);
728 
729     {
730         std::array<GLubyte, 1> colors{1};
731         doClearTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_BYTE,
732                     colors);
733     }
734 
735     {
736         std::array<GLubyte, 2> colors{1, 2};
737         doClearTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_BYTE,
738                     colors);
739     }
740 }
741 
742 // Test reading from YUV420 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromToYUV420IOSurface)743 TEST_P(IOSurfaceClientBufferTest, ReadFromToYUV420IOSurface)
744 {
745     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
746 
747     std::vector<IOSurfacePlaneInfo> planes{{2, 2, 1}, {1, 1, 2}};
748     ScopedIOSurfaceRef ioSurface = CreateIOSurface('420v', planes);
749 
750     {
751         std::array<GLubyte, 1> colors{1};
752         doSampleTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_BYTE,
753                      colors.data(), sizeof(GLubyte) * colors.size(), R);
754     }
755 
756     {
757         std::array<GLubyte, 2> colors{1, 2};
758         doSampleTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_BYTE,
759                      colors.data(), sizeof(GLubyte) * colors.size(), R | G);
760     }
761 }
762 
763 // Test using P010 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest,RenderToP010IOSurface)764 TEST_P(IOSurfaceClientBufferTest, RenderToP010IOSurface)
765 {
766     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
767 
768     std::vector<IOSurfacePlaneInfo> planes{{2, 2, 2}, {1, 1, 4}};
769     ScopedIOSurfaceRef ioSurface = CreateIOSurface('x420', planes);
770 
771     {
772         std::array<GLushort, 1> colors{257};
773         doClearTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_SHORT,
774                     colors);
775     }
776 
777     {
778         std::array<GLushort, 2> colors{257, 514};
779         doClearTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_SHORT,
780                     colors);
781     }
782 }
783 
784 // Test reading from P010 IOSurfaces
TEST_P(IOSurfaceClientBufferTest,ReadFromToP010IOSurface)785 TEST_P(IOSurfaceClientBufferTest, ReadFromToP010IOSurface)
786 {
787     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
788 
789     std::vector<IOSurfacePlaneInfo> planes{{2, 2, 2}, {1, 1, 4}};
790     ScopedIOSurfaceRef ioSurface = CreateIOSurface('x420', planes);
791 
792     {
793         std::array<GLushort, 1> colors{257};
794         doSampleTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_SHORT,
795                      colors.data(), sizeof(GLushort) * colors.size(), R);
796     }
797 
798     {
799         std::array<GLushort, 2> colors{257, 514};
800         doSampleTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_SHORT,
801                      colors.data(), sizeof(GLushort) * colors.size(), R | G);
802     }
803 }
804 
805 // Test blitting from IOSurface
TEST_P(IOSurfaceClientBufferTest,BlitFromIOSurface)806 TEST_P(IOSurfaceClientBufferTest, BlitFromIOSurface)
807 {
808     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
809 
810     doBlitTest(true, 2, 2);
811 }
812 
813 // Test blitting to IOSurface
TEST_P(IOSurfaceClientBufferTest,BlitToIOSurface)814 TEST_P(IOSurfaceClientBufferTest, BlitToIOSurface)
815 {
816     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
817 
818     doBlitTest(false, 2, 2);
819 }
820 
821 // Test using glCopyTexSubImage to copy to BGRX8888 IOSurfaces works.
TEST_P(IOSurfaceClientBufferTest,CopySubImageToBGRX8888IOSurface)822 TEST_P(IOSurfaceClientBufferTest, CopySubImageToBGRX8888IOSurface)
823 {
824     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
825 
826     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
827 
828     GLTexture texture;
829     glBindTexture(getGLTextureTarget(), texture);
830     glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
831     glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
832 
833     // Bind the IOSurface to a texture and clear it.
834     EGLSurface pbuffer;
835     bindIOSurfaceToTexture(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &pbuffer, &texture);
836 
837     // 1. Clear default framebuffer with desired color.
838     GLColor color(1, 2, 3, 4);
839     glClearColor(color.R / 255.f, color.G / 255.f, color.B / 255.f, color.A / 255.f);
840     glClear(GL_COLOR_BUFFER_BIT);
841 
842     // 2. Copy color from default framebuffer to iosurface's bound texture.
843     glCopyTexSubImage2D(getGLTextureTarget(), 0, 0, 0, 0, 0, 1, 1);
844     EXPECT_GL_NO_ERROR();
845 
846     // 3. Do texture sampling verification.
847     doSampleTestWithTexture(texture, R | G | B);
848 }
849 
850 // Test the validation errors for missing attributes for eglCreatePbufferFromClientBuffer with
851 // IOSurface
TEST_P(IOSurfaceClientBufferTest,NegativeValidationMissingAttributes)852 TEST_P(IOSurfaceClientBufferTest, NegativeValidationMissingAttributes)
853 {
854     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
855 
856     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
857 
858     // Success case
859     {
860         // clang-format off
861         const EGLint attribs[] = {
862             EGL_WIDTH,                         10,
863             EGL_HEIGHT,                        10,
864             EGL_IOSURFACE_PLANE_ANGLE,         0,
865             EGL_TEXTURE_TARGET,                getTextureTarget(),
866             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
867             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
868             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
869             EGL_NONE,                          EGL_NONE,
870         };
871         // clang-format off
872 
873         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(), mConfig, attribs);
874         EXPECT_NE(EGL_NO_SURFACE, pbuffer);
875 
876         EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
877         EXPECT_EGL_TRUE(result);
878         EXPECT_EGL_SUCCESS();
879     }
880 
881     // Missing EGL_WIDTH
882     {
883         // clang-format off
884         const EGLint attribs[] = {
885             EGL_HEIGHT,                        10,
886             EGL_IOSURFACE_PLANE_ANGLE,         0,
887             EGL_TEXTURE_TARGET,                getTextureTarget(),
888             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
889             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
890             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
891             EGL_NONE,                          EGL_NONE,
892         };
893         // clang-format on
894 
895         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
896                                                               ioSurface.get(), mConfig, attribs);
897         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
898         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
899     }
900 
901     // Missing EGL_HEIGHT
902     {
903         // clang-format off
904         const EGLint attribs[] = {
905             EGL_WIDTH,                         10,
906             EGL_IOSURFACE_PLANE_ANGLE,         0,
907             EGL_TEXTURE_TARGET,                getTextureTarget(),
908             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
909             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
910             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
911             EGL_NONE,                          EGL_NONE,
912         };
913         // clang-format on
914 
915         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
916                                                               ioSurface.get(), mConfig, attribs);
917         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
918         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
919     }
920 
921     // Missing EGL_IOSURFACE_PLANE_ANGLE
922     {
923         // clang-format off
924         const EGLint attribs[] = {
925             EGL_WIDTH,                         10,
926             EGL_HEIGHT,                        10,
927             EGL_TEXTURE_TARGET,                getTextureTarget(),
928             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
929             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
930             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
931             EGL_NONE,                          EGL_NONE,
932         };
933         // clang-format on
934 
935         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
936                                                               ioSurface.get(), mConfig, attribs);
937         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
938         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
939     }
940 
941     // Missing EGL_TEXTURE_TARGET - EGL_BAD_MATCH from the base spec of
942     // eglCreatePbufferFromClientBuffer
943     {
944         // clang-format off
945         const EGLint attribs[] = {
946             EGL_WIDTH,                         10,
947             EGL_HEIGHT,                        10,
948             EGL_IOSURFACE_PLANE_ANGLE,         0,
949             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
950             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
951             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
952             EGL_NONE,                          EGL_NONE,
953         };
954         // clang-format on
955 
956         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
957                                                               ioSurface.get(), mConfig, attribs);
958         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
959         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
960     }
961 
962     // Missing EGL_TEXTURE_INTERNAL_FORMAT_ANGLE
963     {
964         // clang-format off
965         const EGLint attribs[] = {
966             EGL_WIDTH,                         10,
967             EGL_HEIGHT,                        10,
968             EGL_IOSURFACE_PLANE_ANGLE,         0,
969             EGL_TEXTURE_TARGET,                getTextureTarget(),
970             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
971             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
972             EGL_NONE,                          EGL_NONE,
973         };
974         // clang-format on
975 
976         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
977                                                               ioSurface.get(), mConfig, attribs);
978         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
979         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
980     }
981 
982     // Missing EGL_TEXTURE_FORMAT - EGL_BAD_MATCH from the base spec of
983     // eglCreatePbufferFromClientBuffer
984     {
985         // clang-format off
986         const EGLint attribs[] = {
987             EGL_WIDTH,                         10,
988             EGL_HEIGHT,                        10,
989             EGL_IOSURFACE_PLANE_ANGLE,         0,
990             EGL_TEXTURE_TARGET,                getTextureTarget(),
991             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
992             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
993             EGL_NONE,                          EGL_NONE,
994         };
995         // clang-format on
996 
997         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
998                                                               ioSurface.get(), mConfig, attribs);
999         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1000         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
1001     }
1002 
1003     // Missing EGL_TEXTURE_TYPE_ANGLE
1004     {
1005         // clang-format off
1006         const EGLint attribs[] = {
1007             EGL_WIDTH,                         10,
1008             EGL_HEIGHT,                        10,
1009             EGL_IOSURFACE_PLANE_ANGLE,         0,
1010             EGL_TEXTURE_TARGET,                getTextureTarget(),
1011             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1012             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1013             EGL_NONE,                          EGL_NONE,
1014         };
1015         // clang-format on
1016 
1017         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1018                                                               ioSurface.get(), mConfig, attribs);
1019         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1020         EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
1021     }
1022 }
1023 
1024 // Test the validation errors for bad parameters for eglCreatePbufferFromClientBuffer with IOSurface
TEST_P(IOSurfaceClientBufferTest,NegativeValidationBadAttributes)1025 TEST_P(IOSurfaceClientBufferTest, NegativeValidationBadAttributes)
1026 {
1027     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
1028 
1029     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
1030 
1031     // Success case
1032     {
1033         // clang-format off
1034         const EGLint attribs[] = {
1035             EGL_WIDTH,                         10,
1036             EGL_HEIGHT,                        10,
1037             EGL_IOSURFACE_PLANE_ANGLE,         0,
1038             EGL_TEXTURE_TARGET,                getTextureTarget(),
1039             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1040             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1041             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1042             EGL_NONE,                          EGL_NONE,
1043         };
1044         // clang-format off
1045 
1046         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(), mConfig, attribs);
1047         EXPECT_NE(EGL_NO_SURFACE, pbuffer);
1048 
1049         EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
1050         EXPECT_EGL_TRUE(result);
1051         EXPECT_EGL_SUCCESS();
1052     }
1053 
1054     // EGL_TEXTURE_FORMAT must be EGL_TEXTURE_RGBA
1055     {
1056         // clang-format off
1057         const EGLint attribs[] = {
1058             EGL_WIDTH,                         10,
1059             EGL_HEIGHT,                        10,
1060             EGL_IOSURFACE_PLANE_ANGLE,         0,
1061             EGL_TEXTURE_TARGET,                getTextureTarget(),
1062             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1063             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGB,
1064             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1065             EGL_NONE,                          EGL_NONE,
1066         };
1067         // clang-format on
1068 
1069         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1070                                                               ioSurface.get(), mConfig, attribs);
1071         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1072         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1073     }
1074 
1075     // EGL_WIDTH must be at least 1
1076     {
1077         // clang-format off
1078         const EGLint attribs[] = {
1079             EGL_WIDTH,                         0,
1080             EGL_HEIGHT,                        10,
1081             EGL_IOSURFACE_PLANE_ANGLE,         0,
1082             EGL_TEXTURE_TARGET,                getTextureTarget(),
1083             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1084             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1085             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1086             EGL_NONE,                          EGL_NONE,
1087         };
1088         // clang-format on
1089 
1090         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1091                                                               ioSurface.get(), mConfig, attribs);
1092         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1093         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1094     }
1095 
1096     // EGL_WIDTH must be at most the width of the IOSurface
1097     {
1098         // clang-format off
1099         const EGLint attribs[] = {
1100             EGL_WIDTH,                         11,
1101             EGL_HEIGHT,                        10,
1102             EGL_IOSURFACE_PLANE_ANGLE,         0,
1103             EGL_TEXTURE_TARGET,                getTextureTarget(),
1104             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1105             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1106             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1107             EGL_NONE,                          EGL_NONE,
1108         };
1109         // clang-format on
1110 
1111         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1112                                                               ioSurface.get(), mConfig, attribs);
1113         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1114         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1115     }
1116 
1117     // EGL_HEIGHT must be at least 1
1118     {
1119         // clang-format off
1120         const EGLint attribs[] = {
1121             EGL_WIDTH,                         10,
1122             EGL_HEIGHT,                        0,
1123             EGL_IOSURFACE_PLANE_ANGLE,         0,
1124             EGL_TEXTURE_TARGET,                getTextureTarget(),
1125             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1126             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1127             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1128             EGL_NONE,                          EGL_NONE,
1129         };
1130         // clang-format on
1131 
1132         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1133                                                               ioSurface.get(), mConfig, attribs);
1134         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1135         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1136     }
1137 
1138     // EGL_HEIGHT must be at most the height of the IOSurface
1139     {
1140         // clang-format off
1141         const EGLint attribs[] = {
1142             EGL_WIDTH,                         10,
1143             EGL_HEIGHT,                        11,
1144             EGL_IOSURFACE_PLANE_ANGLE,         0,
1145             EGL_TEXTURE_TARGET,                getTextureTarget(),
1146             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1147             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1148             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1149             EGL_NONE,                          EGL_NONE,
1150         };
1151         // clang-format on
1152 
1153         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1154                                                               ioSurface.get(), mConfig, attribs);
1155         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1156         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1157     }
1158 
1159     // EGL_TEXTURE_FORMAT must be equal to the config's texture target
1160     {
1161         EGLint target      = getTextureTarget();
1162         EGLint wrongTarget = 0;
1163         switch (target)
1164         {
1165             case EGL_TEXTURE_RECTANGLE_ANGLE:
1166                 wrongTarget = EGL_TEXTURE_2D;
1167                 break;
1168             case EGL_TEXTURE_2D:
1169                 wrongTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
1170                 break;
1171             default:
1172                 break;
1173         }
1174         // clang-format off
1175         const EGLint attribs[] = {
1176             EGL_WIDTH,                         10,
1177             EGL_HEIGHT,                        10,
1178             EGL_IOSURFACE_PLANE_ANGLE,         0,
1179             EGL_TEXTURE_TARGET,                wrongTarget,
1180             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1181             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1182             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1183             EGL_NONE,                          EGL_NONE,
1184         };
1185         // clang-format on
1186 
1187         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1188                                                               ioSurface.get(), mConfig, attribs);
1189         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1190         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1191     }
1192 
1193     // EGL_IOSURFACE_PLANE_ANGLE must be at least 0
1194     {
1195         // clang-format off
1196         const EGLint attribs[] = {
1197             EGL_WIDTH,                         10,
1198             EGL_HEIGHT,                        10,
1199             EGL_IOSURFACE_PLANE_ANGLE,         -1,
1200             EGL_TEXTURE_TARGET,                getTextureTarget(),
1201             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1202             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1203             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1204             EGL_NONE,                          EGL_NONE,
1205         };
1206         // clang-format on
1207 
1208         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1209                                                               ioSurface.get(), mConfig, attribs);
1210         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1211         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1212     }
1213 
1214     // EGL_IOSURFACE_PLANE_ANGLE must less than the number of planes of the IOSurface
1215     {
1216         // clang-format off
1217         const EGLint attribs[] = {
1218             EGL_WIDTH,                         10,
1219             EGL_HEIGHT,                        10,
1220             EGL_IOSURFACE_PLANE_ANGLE,         1,
1221             EGL_TEXTURE_TARGET,                getTextureTarget(),
1222             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
1223             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1224             EGL_TEXTURE_TYPE_ANGLE,            GL_UNSIGNED_BYTE,
1225             EGL_NONE,                          EGL_NONE,
1226         };
1227         // clang-format on
1228 
1229         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1230                                                               ioSurface.get(), mConfig, attribs);
1231         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1232         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1233     }
1234 
1235     // The internal format / type most be listed in the table
1236     {
1237         // clang-format off
1238         const EGLint attribs[] = {
1239             EGL_WIDTH,                         10,
1240             EGL_HEIGHT,                        10,
1241             EGL_IOSURFACE_PLANE_ANGLE,         0,
1242             EGL_TEXTURE_TARGET,                getTextureTarget(),
1243             EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGBA,
1244             EGL_TEXTURE_FORMAT,                EGL_TEXTURE_RGBA,
1245             EGL_TEXTURE_TYPE_ANGLE,            GL_FLOAT,
1246             EGL_NONE,                          EGL_NONE,
1247         };
1248         // clang-format on
1249 
1250         EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
1251                                                               ioSurface.get(), mConfig, attribs);
1252         EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
1253         EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1254     }
1255 }
1256 
1257 // Test IOSurface pbuffers can be made current
TEST_P(IOSurfaceClientBufferTest,MakeCurrent)1258 TEST_P(IOSurfaceClientBufferTest, MakeCurrent)
1259 {
1260     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
1261 
1262     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
1263 
1264     EGLSurface pbuffer;
1265     createIOSurfacePbuffer(ioSurface, 10, 10, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &pbuffer);
1266 
1267     EGLContext context = getEGLWindow()->getContext();
1268     EGLBoolean result  = eglMakeCurrent(mDisplay, pbuffer, pbuffer, context);
1269     EXPECT_EGL_TRUE(result);
1270     EXPECT_EGL_SUCCESS();
1271     // The test harness expects the EGL state to be restored before the test exits.
1272     result = eglMakeCurrent(mDisplay, getEGLWindow()->getSurface(), getEGLWindow()->getSurface(),
1273                             context);
1274     EXPECT_EGL_TRUE(result);
1275     EXPECT_EGL_SUCCESS();
1276 }
1277 
1278 // Test reading from BGRX8888 IOSurfaces with bound texture's base/max level set to zero.
1279 // This to verify that changing base/level shouldn't delete the binding.
1280 // bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1337324
TEST_P(IOSurfaceClientBufferTest,ReadFromBGRX8888IOSurfaceWithTexBaseMaxLevelSetToZero)1281 TEST_P(IOSurfaceClientBufferTest, ReadFromBGRX8888IOSurfaceWithTexBaseMaxLevelSetToZero)
1282 {
1283     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
1284     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
1285 
1286     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
1287 
1288     GLColor color(3, 2, 1, 4);
1289     doSampleTestWithExtraSteps(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color),
1290                                R | G | B, /* extra steps */ [this] {
1291                                    glTexParameteri(getGLTextureTarget(), GL_TEXTURE_BASE_LEVEL, 0);
1292                                    glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAX_LEVEL, 0);
1293                                });
1294 }
1295 
1296 // Test that the following scenario works:
1297 // - change IOSurface bound texture's max level to 0.
1298 // - attach IOSurface bound texture to a FBO 1.
1299 // - bind FBO 1
1300 // - clear FBO 1 -> this should trigger render targets initialization in backends.
1301 // - bind FBO 0.
1302 // - draw IOSurface bound texture to FBO 0.
1303 //   -> In the past, this could trigger the texture's render targets invalidation in metal backend.
1304 //   See https://issues.chromium.org/issues/335353385
1305 // - bind FBO 1
1306 // - blit FBO 0 to FBO 1.
1307 //   -> this will reconstruct render pass descriptor in metal backend.
1308 // - flush to restart render encoder with new render pass descriptor.
1309 // - draw.
TEST_P(IOSurfaceClientBufferTest,SetMaxLevelWouldInvalidateRenderTargetBug)1310 TEST_P(IOSurfaceClientBufferTest, SetMaxLevelWouldInvalidateRenderTargetBug)
1311 {
1312     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
1313     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
1314 
1315     ANGLE_GL_PROGRAM(blueProgram, angle::essl1_shaders::vs::Simple(),
1316                      angle::essl1_shaders::fs::Blue());
1317 
1318     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
1319 
1320     GLTexture texture;
1321     glBindTexture(getGLTextureTarget(), texture);
1322 
1323     // Bind the IOSurface to a texture.
1324     EGLSurface pbuffer;
1325     bindIOSurfaceToTexture(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &pbuffer, &texture);
1326 
1327     // 1. Change the texture's max level to 0.
1328     glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAX_LEVEL, 0);
1329     EXPECT_GL_NO_ERROR();
1330 
1331     // 2. Attach IOSurface bound texture to a FBO and clear it.
1332     GLFramebuffer fbo;
1333     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1334     EXPECT_GL_NO_ERROR();
1335     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(), texture, 0);
1336     glEnable(GL_BLEND);
1337     glBlendFunc(GL_ONE, GL_ONE);
1338     glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
1339     glClear(GL_COLOR_BUFFER_BIT);
1340 
1341     // 3. Draw IOSurface bound texture to default FBO.
1342     glBindFramebuffer(GL_FRAMEBUFFER, 0);
1343     doSampleTestWithTexture(texture, R | G | B);
1344 
1345     // 3. Draw to custom FBO again
1346     glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
1347     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1348     glClear(GL_COLOR_BUFFER_BIT);
1349     // Using a blit is important: it will trigger render pass reconstruction in
1350     // metal backend due to DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 dirty bit.
1351     glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1352     glFlush();  // flush so that render encoder will be recreated again in metal backend.
1353     glUseProgram(blueProgram);
1354     drawQuad(blueProgram, angle::essl1_shaders::PositionAttrib(), 0.5f);
1355     glFlush();
1356 
1357     // Expect the final color to be accumulated color
1358     glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
1359     EXPECT_GL_NO_ERROR();
1360     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(1, 2, 255, 255));
1361 }
1362 
1363 // Test using GL_EXT_multisampled_render_to_texture to render to BGRX IOSurface.
TEST_P(IOSurfaceClientBufferTest,MultisampledRenderToTextureBGRX)1364 TEST_P(IOSurfaceClientBufferTest, MultisampledRenderToTextureBGRX)
1365 {
1366     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
1367 
1368     ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
1369 
1370     ANGLE_GL_PROGRAM(colorProgram, angle::essl1_shaders::vs::Simple(),
1371                      angle::essl1_shaders::fs::UniformColor());
1372 
1373     ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
1374 
1375     GLTexture texture;
1376     glBindTexture(getGLTextureTarget(), texture);
1377 
1378     // Bind the IOSurface to a texture.
1379     EGLSurface pbuffer;
1380     bindIOSurfaceToTexture(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &pbuffer, &texture);
1381 
1382     // Attach IOSurface bound texture to a single sampled FBO and clear it.
1383     GLFramebuffer singleSampledFbo;
1384     glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFbo);
1385     EXPECT_GL_NO_ERROR();
1386     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(), texture, 0);
1387     glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
1388     glClear(GL_COLOR_BUFFER_BIT);
1389 
1390     // Attach IOSurface to a multisampled FBO and draw translucent blue color
1391     GLFramebuffer multisampledSampledFbo;
1392     glBindFramebuffer(GL_FRAMEBUFFER, multisampledSampledFbo);
1393     EXPECT_GL_NO_ERROR();
1394     glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getGLTextureTarget(),
1395                                          texture, 0, 4);
1396     glEnable(GL_BLEND);
1397     glBlendFunc(GL_ONE, GL_ONE);
1398     glUseProgram(colorProgram);
1399     const GLint colorUniformLocation =
1400         glGetUniformLocation(colorProgram, angle::essl1_shaders::ColorUniform());
1401     ASSERT_NE(colorUniformLocation, -1);
1402     glUniform4f(colorUniformLocation, 0, 0, 1, 0.5f);
1403     drawQuad(colorProgram, angle::essl1_shaders::PositionAttrib(), 0.5f);
1404 
1405     // Expect the final color to be accumulated color
1406     glBindFramebuffer(GL_FRAMEBUFFER, singleSampledFbo);
1407     EXPECT_GL_NO_ERROR();
1408     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(1, 2, 255, 255));
1409 }
1410 
1411 // TODO([email protected]): Test setting width and height to less than the IOSurface's work as
1412 // expected.
1413 
1414 ANGLE_INSTANTIATE_TEST(IOSurfaceClientBufferTest,
1415                        ES2_OPENGL(),
1416                        ES3_OPENGL(),
1417                        ES2_VULKAN_SWIFTSHADER(),
1418                        ES3_VULKAN_SWIFTSHADER(),
1419                        ES2_METAL(),
1420                        ES3_METAL(),
1421                        ES3_METAL()
1422                            .enable(Feature::EnableMultisampledRenderToTextureOnNonTilers)
1423                            .enable(Feature::EmulateDontCareLoadWithRandomClear));
1424