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