• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // EGLStreamTest:
7 //   Tests pertaining to egl::Stream.
8 //
9 
10 #include <gtest/gtest.h>
11 
12 #include <vector>
13 
14 #include "media/yuvtest.inl"
15 #include "test_utils/ANGLETest.h"
16 #include "test_utils/gl_raii.h"
17 #include "util/EGLWindow.h"
18 #include "util/OSWindow.h"
19 
20 using namespace angle;
21 
22 namespace
23 {
24 
CheckTextureSupport(ID3D11Device * device,DXGI_FORMAT format)25 bool CheckTextureSupport(ID3D11Device *device, DXGI_FORMAT format)
26 {
27     HRESULT result;
28     UINT formatSupport;
29     result = device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
30     if (result == E_FAIL)
31     {
32         return false;
33     }
34     return (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
35 }
36 
CheckNV12TextureSupport(ID3D11Device * device)37 bool CheckNV12TextureSupport(ID3D11Device *device)
38 {
39     return CheckTextureSupport(device, DXGI_FORMAT_NV12);
40 }
41 
CheckP010TextureSupport(ID3D11Device * device)42 bool CheckP010TextureSupport(ID3D11Device *device)
43 {
44     return CheckTextureSupport(device, DXGI_FORMAT_P010);
45 }
46 
47 class EGLStreamTest : public ANGLETest
48 {
49   protected:
EGLStreamTest()50     EGLStreamTest()
51     {
52         setWindowWidth(128);
53         setWindowHeight(128);
54         setConfigRedBits(8);
55         setConfigGreenBits(8);
56         setConfigBlueBits(8);
57         setConfigAlphaBits(8);
58         setConfigDepthBits(24);
59     }
60 };
61 
62 // Tests validation of the stream API
TEST_P(EGLStreamTest,StreamValidationTest)63 TEST_P(EGLStreamTest, StreamValidationTest)
64 {
65     EGLWindow *window            = getEGLWindow();
66     EGLDisplay display           = window->getDisplay();
67     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
68     if (strstr(extensionsString, "EGL_KHR_stream") == nullptr)
69     {
70         std::cout << "Stream extension not supported" << std::endl;
71         return;
72     }
73 
74     const EGLint streamAttributesBad[] = {
75         EGL_STREAM_STATE_KHR,
76         0,
77         EGL_NONE,
78         EGL_PRODUCER_FRAME_KHR,
79         0,
80         EGL_NONE,
81         EGL_CONSUMER_FRAME_KHR,
82         0,
83         EGL_NONE,
84         EGL_CONSUMER_LATENCY_USEC_KHR,
85         -1,
86         EGL_NONE,
87         EGL_RED_SIZE,
88         EGL_DONT_CARE,
89         EGL_NONE,
90     };
91 
92     // Validate create stream attributes
93     EGLStreamKHR stream = eglCreateStreamKHR(display, &streamAttributesBad[0]);
94     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
95     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
96 
97     stream = eglCreateStreamKHR(display, &streamAttributesBad[3]);
98     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
99     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
100 
101     stream = eglCreateStreamKHR(display, &streamAttributesBad[6]);
102     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
103     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
104 
105     stream = eglCreateStreamKHR(display, &streamAttributesBad[9]);
106     ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
107     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
108 
109     stream = eglCreateStreamKHR(display, &streamAttributesBad[12]);
110     ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
111     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
112 
113     const EGLint streamAttributes[] = {
114         EGL_CONSUMER_LATENCY_USEC_KHR,
115         0,
116         EGL_NONE,
117     };
118 
119     stream = eglCreateStreamKHR(EGL_NO_DISPLAY, streamAttributes);
120     ASSERT_EGL_ERROR(EGL_BAD_DISPLAY);
121     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
122 
123     // Create an actual stream
124     stream = eglCreateStreamKHR(display, streamAttributes);
125     ASSERT_EGL_SUCCESS();
126     ASSERT_NE(EGL_NO_STREAM_KHR, stream);
127 
128     // Assert it is in the created state
129     EGLint state;
130     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
131     ASSERT_EGL_SUCCESS();
132     ASSERT_EQ(EGL_STREAM_STATE_CREATED_KHR, state);
133 
134     // Test getting and setting the latency
135     EGLint latency = 10;
136     eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, latency);
137     ASSERT_EGL_SUCCESS();
138     eglQueryStreamKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, &latency);
139     ASSERT_EGL_SUCCESS();
140     ASSERT_EQ(10, latency);
141     eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, -1);
142     ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
143     ASSERT_EQ(10, latency);
144 
145     // Test the 64-bit queries
146     EGLuint64KHR value;
147     eglQueryStreamu64KHR(display, stream, EGL_CONSUMER_FRAME_KHR, &value);
148     ASSERT_EGL_SUCCESS();
149     eglQueryStreamu64KHR(display, stream, EGL_PRODUCER_FRAME_KHR, &value);
150     ASSERT_EGL_SUCCESS();
151 
152     // Destroy the stream
153     eglDestroyStreamKHR(display, stream);
154     ASSERT_EGL_SUCCESS();
155 }
156 
157 // Tests validation of stream consumer gltexture API
TEST_P(EGLStreamTest,StreamConsumerGLTextureValidationTest)158 TEST_P(EGLStreamTest, StreamConsumerGLTextureValidationTest)
159 {
160     EGLWindow *window            = getEGLWindow();
161     EGLDisplay display           = window->getDisplay();
162     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
163     if (strstr(extensionsString, "EGL_KHR_stream_consumer_gltexture") == nullptr)
164     {
165         std::cout << "Stream consumer gltexture extension not supported" << std::endl;
166         return;
167     }
168 
169     const EGLint streamAttributes[] = {
170         EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
171     };
172 
173     EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
174     ASSERT_EGL_SUCCESS();
175 
176     EGLBoolean result = eglStreamConsumerGLTextureExternalKHR(display, stream);
177     ASSERT_EGL_FALSE(result);
178     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
179 
180     GLuint tex;
181     glGenTextures(1, &tex);
182     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
183     result = eglStreamConsumerGLTextureExternalKHR(display, stream);
184     ASSERT_EGL_TRUE(result);
185     ASSERT_EGL_SUCCESS();
186 
187     EGLint state;
188     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
189     ASSERT_EGL_SUCCESS();
190     ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state);
191 
192     eglDestroyStreamKHR(display, stream);
193     ASSERT_EGL_SUCCESS();
194 }
195 
196 // Tests validation of stream consumer gltexture yuv API
TEST_P(EGLStreamTest,StreamConsumerGLTextureYUVValidationTest)197 TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVValidationTest)
198 {
199     EGLWindow *window            = getEGLWindow();
200     EGLDisplay display           = window->getDisplay();
201     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
202     if (strstr(extensionsString, "EGL_NV_stream_consumer_gltexture_yuv") == nullptr)
203     {
204         std::cout << "Stream consumer gltexture yuv extension not supported" << std::endl;
205         return;
206     }
207 
208     const EGLint streamAttributes[] = {
209         EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
210     };
211 
212     EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
213     ASSERT_EGL_SUCCESS();
214 
215     EGLAttrib consumerAttributesBad[] = {
216         EGL_COLOR_BUFFER_TYPE,
217         EGL_YUV_BUFFER_EXT,  // 0
218         EGL_YUV_NUMBER_OF_PLANES_EXT,
219         0,
220         EGL_NONE,
221         EGL_COLOR_BUFFER_TYPE,
222         EGL_YUV_BUFFER_EXT,  // 5
223         EGL_YUV_NUMBER_OF_PLANES_EXT,
224         1,
225         EGL_NONE,
226         EGL_COLOR_BUFFER_TYPE,
227         EGL_YUV_BUFFER_EXT,  // 10
228         EGL_YUV_NUMBER_OF_PLANES_EXT,
229         1,
230         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
231         9999,
232         EGL_NONE,
233         EGL_COLOR_BUFFER_TYPE,
234         EGL_YUV_BUFFER_EXT,  // 17
235         EGL_YUV_NUMBER_OF_PLANES_EXT,
236         1,
237         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
238         0,
239         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
240         1,
241         EGL_NONE,
242         EGL_COLOR_BUFFER_TYPE,
243         EGL_YUV_BUFFER_EXT,  // 26
244         EGL_YUV_NUMBER_OF_PLANES_EXT,
245         2,
246         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
247         0,
248         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
249         0,
250         EGL_NONE,
251     };
252 
253     EGLAttrib consumerAttributes[] = {
254         EGL_COLOR_BUFFER_TYPE,
255         EGL_YUV_BUFFER_EXT,
256         EGL_YUV_NUMBER_OF_PLANES_EXT,
257         2,
258         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
259         0,
260         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
261         1,
262         EGL_NONE,
263     };
264 
265     EGLBoolean result =
266         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[0]);
267     ASSERT_EGL_FALSE(result);
268     ASSERT_EGL_ERROR(EGL_BAD_MATCH);
269 
270     result =
271         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[5]);
272     ASSERT_EGL_FALSE(result);
273     ASSERT_EGL_ERROR(EGL_BAD_MATCH);
274 
275     result =
276         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[10]);
277     ASSERT_EGL_FALSE(result);
278     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
279 
280     result =
281         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[17]);
282     ASSERT_EGL_FALSE(result);
283     ASSERT_EGL_ERROR(EGL_BAD_MATCH);
284 
285     result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
286     ASSERT_EGL_FALSE(result);
287     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
288 
289     GLuint tex[2];
290     glGenTextures(2, tex);
291     glActiveTexture(GL_TEXTURE0);
292     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
293     glActiveTexture(GL_TEXTURE1);
294     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
295 
296     result =
297         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[26]);
298     ASSERT_EGL_FALSE(result);
299     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
300 
301     result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
302     ASSERT_EGL_TRUE(result);
303     ASSERT_EGL_SUCCESS();
304 
305     EGLint state;
306     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
307     ASSERT_EGL_SUCCESS();
308     ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state);
309 
310     eglDestroyStreamKHR(display, stream);
311     ASSERT_EGL_SUCCESS();
312 }
313 
314 // Tests that deleting a texture invalidates the associated stream
TEST_P(EGLStreamTest,StreamConsumerGLTextureYUVDeletionTest)315 TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVDeletionTest)
316 {
317     EGLWindow *window            = getEGLWindow();
318     EGLDisplay display           = window->getDisplay();
319     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
320     if (strstr(extensionsString, "EGL_ANGLE_stream_producer_d3d_texture") == nullptr)
321     {
322         std::cout << "Stream producer d3d texture not supported" << std::endl;
323         return;
324     }
325 
326     const EGLint streamAttributes[] = {
327         EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
328     };
329 
330     EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
331     ASSERT_EGL_SUCCESS();
332 
333     EGLAttrib consumerAttributes[] = {
334         EGL_COLOR_BUFFER_TYPE,
335         EGL_YUV_BUFFER_EXT,
336         EGL_YUV_NUMBER_OF_PLANES_EXT,
337         2,
338         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
339         0,
340         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
341         1,
342         EGL_NONE,
343     };
344 
345     GLuint tex[2];
346     glGenTextures(2, tex);
347     glActiveTexture(GL_TEXTURE0);
348     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
349     glActiveTexture(GL_TEXTURE1);
350     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
351 
352     EGLBoolean result =
353         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
354     ASSERT_EGL_TRUE(result);
355     ASSERT_EGL_SUCCESS();
356 
357     EGLAttrib producerAttributes[] = {
358         EGL_NONE,
359     };
360 
361     result = eglCreateStreamProducerD3DTextureANGLE(display, stream, producerAttributes);
362     ASSERT_EGL_TRUE(result);
363     ASSERT_EGL_SUCCESS();
364 
365     EGLint state;
366     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
367     ASSERT_EGL_SUCCESS();
368     ASSERT_EQ(EGL_STREAM_STATE_EMPTY_KHR, state);
369 
370     // Delete the first texture, which should be enough to invalidate the stream
371     glDeleteTextures(1, tex);
372 
373     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
374     ASSERT_EGL_SUCCESS();
375     ASSERT_EQ(EGL_STREAM_STATE_DISCONNECTED_KHR, state);
376 
377     eglDestroyStreamKHR(display, stream);
378     ASSERT_EGL_SUCCESS();
379 }
380 
381 class D3D11TextureStreamSamplingTest : public ANGLETest
382 {
383   protected:
testSetUp()384     void testSetUp() override
385     {
386         EGLWindow *window = getEGLWindow();
387         mDisplay          = window->getDisplay();
388         if (!IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANGLE_stream_producer_d3d_texture"))
389         {
390             std::cout << "Stream producer d3d texture not supported" << std::endl;
391             return;
392         }
393 
394         glGenRenderbuffers(1, &mRB);
395         glBindRenderbuffer(GL_RENDERBUFFER, mRB);
396         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 2, 2);
397         glBindRenderbuffer(GL_RENDERBUFFER, 0);
398 
399         glGenFramebuffers(1, &mFB);
400         glBindFramebuffer(GL_FRAMEBUFFER, mFB);
401         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRB);
402         ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
403 
404         glViewport(0, 0, 2, 2);
405         glClearColor(1, 0, 0, 1);
406         glClear(GL_COLOR_BUFFER_BIT);
407         ASSERT_GL_NO_ERROR();
408 
409         uint32_t pixel;
410         glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
411         ASSERT_EQ(pixel, 0xff0000ff);
412 
413         mStream = eglCreateStreamKHR(mDisplay, nullptr);
414         ASSERT_EGL_SUCCESS();
415 
416         EGLDeviceEXT eglDevice;
417         eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, (EGLAttrib *)&eglDevice);
418         eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, (EGLAttrib *)&mD3D);
419     }
420 
testTearDown()421     void testTearDown() override
422     {
423         EGLBoolean result = eglDestroyStreamKHR(mDisplay, mStream);
424         ASSERT_EGL_TRUE(result);
425         ASSERT_EGL_SUCCESS();
426 
427         glDeleteRenderbuffers(1, &mRB);
428         glDeleteFramebuffers(1, &mFB);
429     }
430 
431     EGLDisplay mDisplay  = 0;
432     EGLStreamKHR mStream = 0;
433     GLuint mRB           = 0;
434     GLuint mFB           = 0;
435     ID3D11Device *mD3D;
436 };
437 
438 // Test RGBA texture sampling via EGLStreams
TEST_P(D3D11TextureStreamSamplingTest,RGBA)439 TEST_P(D3D11TextureStreamSamplingTest, RGBA)
440 {
441     EGLWindow *window  = getEGLWindow();
442     EGLDisplay display = window->getDisplay();
443     ANGLE_SKIP_TEST_IF(
444         !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture"));
445 
446     constexpr char kVertShader[] = R"(
447         attribute vec4 aPos;
448         varying vec2 vTexCoord;
449         void main()
450         {
451             gl_Position = aPos;
452             vTexCoord = gl_Position.xy * 0.5 + 0.5;
453         }
454     )";
455     constexpr char kFragShader[] = R"(
456         #extension GL_NV_EGL_stream_consumer_external : require
457         precision mediump float;
458         uniform samplerExternalOES uTex;
459         varying vec2 vTexCoord;
460         void main()
461         {
462             gl_FragColor = texture2D(uTex, vTexCoord);
463         }
464     )";
465     ANGLE_GL_PROGRAM(prog, kVertShader, kFragShader);
466     glUseProgram(prog);
467     glUniform1i(glGetUniformLocation(prog, "uTex"), 0);
468 
469     GLTexture tex;
470     glActiveTexture(GL_TEXTURE0);
471     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
472     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
473     ASSERT_GL_NO_ERROR();
474 
475     EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV(mDisplay, mStream, nullptr);
476     ASSERT_EGL_TRUE(result);
477     ASSERT_EGL_SUCCESS();
478     glActiveTexture(GL_TEXTURE3);  // Set to an unused slot to ensure StreamConsumer picked up
479                                    // the current slot.
480 
481     result = eglCreateStreamProducerD3DTextureANGLE(mDisplay, mStream, nullptr);
482     ASSERT_EGL_TRUE(result);
483     ASSERT_EGL_SUCCESS();
484 
485     // Create and post the d3d11 texture
486 
487     D3D11_TEXTURE2D_DESC desc = {};
488     desc.Width                = 1;
489     desc.Height               = 1;
490     desc.Format               = DXGI_FORMAT_R8G8B8A8_UNORM;
491     desc.MipLevels            = 1;
492     desc.ArraySize            = 1;
493     desc.SampleDesc.Count     = 1;
494     desc.Usage                = D3D11_USAGE_DEFAULT;
495     desc.BindFlags            = D3D11_BIND_SHADER_RESOURCE;
496 
497     constexpr uint8_t texData[] = {0x10, 0x20, 0x30, 0x40};
498     D3D11_SUBRESOURCE_DATA subres;
499     subres.pSysMem     = texData;
500     subres.SysMemPitch = 4;
501 
502     ID3D11Texture2D *texture = nullptr;
503     (void)mD3D->CreateTexture2D(&desc, &subres, &texture);
504     ASSERT_NE(nullptr, texture);
505 
506     result = eglStreamPostD3DTextureANGLE(mDisplay, mStream, (void *)texture, nullptr);
507     ASSERT_EGL_TRUE(result);
508     ASSERT_EGL_SUCCESS();
509 
510     // Sample and test
511 
512     result = eglStreamConsumerAcquireKHR(mDisplay, mStream);
513     ASSERT_EGL_TRUE(result);
514     ASSERT_EGL_SUCCESS();
515 
516     drawQuad(prog, "aPos", 0.0);
517 
518     uint32_t pixel;
519     glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
520     ASSERT_GL_NO_ERROR();
521     ASSERT_EQ(pixel, static_cast<uint32_t>(0x40302010));
522 
523     result = eglStreamConsumerReleaseKHR(mDisplay, mStream);
524     ASSERT_EGL_TRUE(result);
525     ASSERT_EGL_SUCCESS();
526 }
527 
528 // Test NV12 texture sampling via EGLStreams
TEST_P(D3D11TextureStreamSamplingTest,NV12)529 TEST_P(D3D11TextureStreamSamplingTest, NV12)
530 {
531     EGLWindow *window  = getEGLWindow();
532     EGLDisplay display = window->getDisplay();
533     ANGLE_SKIP_TEST_IF(
534         !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture"));
535     ANGLE_SKIP_TEST_IF(!CheckNV12TextureSupport(mD3D));
536 
537     constexpr char kVertShader[] = R"(
538         attribute vec4 aPos;
539         varying vec2 vTexCoord;
540         void main()
541         {
542             gl_Position = aPos;
543             vTexCoord = gl_Position.xy * 0.5 + 0.5;
544         }
545     )";
546     const char kFragShader[]     = R"(
547         #extension GL_NV_EGL_stream_consumer_external : require
548         precision mediump float;
549         uniform samplerExternalOES uTexY;
550         uniform samplerExternalOES uTexUV;
551         varying vec2 vTexCoord;
552         void main()
553         {
554             gl_FragColor.r = texture2D(uTexY, vTexCoord).r;
555             gl_FragColor.gb = texture2D(uTexUV, vTexCoord).rg;
556             gl_FragColor.a = 1.0;
557         }
558     )";
559     ANGLE_GL_PROGRAM(prog, kVertShader, kFragShader);
560     glUseProgram(prog);
561     glUniform1i(glGetUniformLocation(prog, "uTexY"), 0);
562     glUniform1i(glGetUniformLocation(prog, "uTexUV"), 1);
563 
564     ASSERT_GL_NO_ERROR();
565 
566     GLTexture tex[2];
567     glActiveTexture(GL_TEXTURE0);
568     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
569     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
570     ASSERT_GL_NO_ERROR();
571     glActiveTexture(GL_TEXTURE1);
572     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
573     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
574     ASSERT_GL_NO_ERROR();
575 
576     glActiveTexture(GL_TEXTURE3);  // Set to an unused slot to ensure StreamConsumer picks up
577                                    // the current slot.
578     constexpr EGLAttrib consumerAttributes[] = {
579         EGL_COLOR_BUFFER_TYPE,
580         EGL_YUV_BUFFER_EXT,
581         EGL_YUV_NUMBER_OF_PLANES_EXT,
582         2,
583         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
584         0,
585         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
586         1,
587         EGL_NONE,
588     };
589     EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV(
590         mDisplay, mStream, const_cast<EGLAttrib *>(consumerAttributes));
591     ASSERT_EGL_TRUE(result);
592     ASSERT_EGL_SUCCESS();
593 
594     result = eglCreateStreamProducerD3DTextureANGLE(mDisplay, mStream, nullptr);
595     ASSERT_EGL_TRUE(result);
596     ASSERT_EGL_SUCCESS();
597 
598     // Create and post the d3d11 texture
599 
600     D3D11_TEXTURE2D_DESC desc = {};
601     desc.Width                = 2;
602     desc.Height               = 2;
603     desc.Format               = DXGI_FORMAT_NV12;
604     desc.MipLevels            = 1;
605     desc.ArraySize            = 1;
606     desc.SampleDesc.Count     = 1;
607     desc.Usage                = D3D11_USAGE_DEFAULT;
608     desc.BindFlags            = D3D11_BIND_SHADER_RESOURCE;
609 
610     /* DXGI_FORMAT_NV12:
611      * Width and height must be even.
612      * Direct3D 11 staging resources and initData parameters for this format use
613      * (rowPitch * (height + (height / 2))) bytes.
614      * The first (SysMemPitch * height) bytes are the Y plane, the remaining
615      * (SysMemPitch * (height / 2)) bytes are the UV plane.
616      */
617     constexpr uint8_t texData[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60};
618     D3D11_SUBRESOURCE_DATA subres;
619     subres.pSysMem     = texData;
620     subres.SysMemPitch = 2;
621 
622     ID3D11Texture2D *texture = nullptr;
623     (void)mD3D->CreateTexture2D(&desc, &subres, &texture);
624     ASSERT_NE(nullptr, texture);
625 
626     result = eglStreamPostD3DTextureANGLE(mDisplay, mStream, (void *)texture, nullptr);
627     ASSERT_EGL_TRUE(result);
628     ASSERT_EGL_SUCCESS();
629 
630     // Sample and test
631 
632     result = eglStreamConsumerAcquireKHR(mDisplay, mStream);
633     ASSERT_EGL_TRUE(result);
634     ASSERT_EGL_SUCCESS();
635 
636     drawQuad(prog, "aPos", 0.0);
637     uint32_t pixel;
638     glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
639     ASSERT_EQ(pixel, 0xff605010);
640 
641     glReadPixels(1, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
642     ASSERT_EQ(pixel, 0xff605020);
643 
644     glReadPixels(0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
645     ASSERT_EQ(pixel, 0xff605030);
646 
647     glReadPixels(1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
648     ASSERT_EQ(pixel, 0xff605040);
649 
650     result = eglStreamConsumerReleaseKHR(mDisplay, mStream);
651     ASSERT_EGL_TRUE(result);
652     ASSERT_EGL_SUCCESS();
653 }
654 
655 // End2end test for rendering an NV12 texture. Renders a YUV quad, reads back the RGB values, and
656 // ensures they are correct
TEST_P(EGLStreamTest,StreamProducerTextureNV12End2End)657 TEST_P(EGLStreamTest, StreamProducerTextureNV12End2End)
658 {
659     EGLWindow *window  = getEGLWindow();
660     EGLDisplay display = window->getDisplay();
661     ANGLE_SKIP_TEST_IF(
662         !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture"));
663 
664     bool useESSL3Shaders =
665         getClientMajorVersion() >= 3 && IsGLExtensionEnabled("GL_OES_EGL_image_external_essl3");
666 
667     // yuv to rgb conversion shader using Microsoft's given conversion formulas
668     const char *yuvVS = nullptr;
669     const char *yuvPS = nullptr;
670     if (useESSL3Shaders)
671     {
672         yuvVS =
673             "#version 300 es\n"
674             "in highp vec4 position;\n"
675             "out vec2 texcoord;\n"
676             "void main(void)\n"
677             "{\n"
678             "    gl_Position = position;\n"
679             "    texcoord = (position.xy * 0.5) + 0.5;\n"
680             "    texcoord.y = 1.0 - texcoord.y;\n"
681             "}\n";
682         yuvPS =
683             "#version 300 es\n"
684             "#extension GL_OES_EGL_image_external_essl3 : require\n"
685             "#extension GL_NV_EGL_stream_consumer_external : require\n"
686             "precision highp float;\n"
687             "in vec2 texcoord;\n"
688             "out vec4 color;\n"
689             "uniform samplerExternalOES y;\n"
690             "uniform samplerExternalOES uv\n;"
691             "void main(void)\n"
692             "{\n"
693             "    float c = texture(y, texcoord).r - (16.0 / 256.0);\n"
694             "    float d = texture(uv, texcoord).r - 0.5;\n"
695             "    float e = texture(uv, texcoord).g - 0.5;\n"
696             "    float r = 1.164383 * c + 1.596027 * e;\n"
697             "    float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n"
698             "    float b = 1.164383 * c + 2.017232 * d;\n"
699             "    color = vec4(r, g, b, 1.0);\n"
700             "}\n";
701     }
702     else
703     {
704         yuvVS =
705             "attribute highp vec4 position;\n"
706             "varying vec2 texcoord;\n"
707             "void main(void)\n"
708             "{\n"
709             "    gl_Position = position;\n"
710             "    texcoord = (position.xy * 0.5) + 0.5;\n"
711             "    texcoord.y = 1.0 - texcoord.y;\n"
712             "}\n";
713 
714         yuvPS =
715             "#extension GL_NV_EGL_stream_consumer_external : require\n"
716             "precision highp float;\n"
717             "varying vec2 texcoord;\n"
718             "uniform samplerExternalOES y;\n"
719             "uniform samplerExternalOES uv\n;"
720             "void main(void)\n"
721             "{\n"
722             "    float c = texture2D(y, texcoord).r - (16.0 / 256.0);\n"
723             "    float d = texture2D(uv, texcoord).r - 0.5;\n"
724             "    float e = texture2D(uv, texcoord).g - 0.5;\n"
725             "    float r = 1.164383 * c + 1.596027 * e;\n"
726             "    float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n"
727             "    float b = 1.164383 * c + 2.017232 * d;\n"
728             "    gl_FragColor = vec4(r, g, b, 1.0);\n"
729             "}\n";
730     }
731 
732     ANGLE_GL_PROGRAM(program, yuvVS, yuvPS);
733     GLuint yUniform  = glGetUniformLocation(program, "y");
734     GLuint uvUniform = glGetUniformLocation(program, "uv");
735 
736     // Fetch the D3D11 device
737     EGLDeviceEXT eglDevice;
738     eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, (EGLAttrib *)&eglDevice);
739     ID3D11Device *device;
740     eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, (EGLAttrib *)&device);
741 
742     ANGLE_SKIP_TEST_IF(!CheckNV12TextureSupport(device));
743 
744     // Create the NV12 D3D11 texture
745     D3D11_TEXTURE2D_DESC desc;
746     desc.Width              = yuvtest_width;
747     desc.Height             = yuvtest_height;
748     desc.Format             = DXGI_FORMAT_NV12;
749     desc.MipLevels          = 1;
750     desc.ArraySize          = 1;
751     desc.SampleDesc.Count   = 1;
752     desc.SampleDesc.Quality = 0;
753     desc.Usage              = D3D11_USAGE_DEFAULT;
754     desc.BindFlags          = D3D11_BIND_SHADER_RESOURCE;
755     desc.CPUAccessFlags     = 0;
756     desc.MiscFlags          = 0;
757 
758     D3D11_SUBRESOURCE_DATA subres;
759     subres.pSysMem          = yuvtest_data;
760     subres.SysMemPitch      = yuvtest_width;
761     subres.SysMemSlicePitch = yuvtest_width * yuvtest_height * 3 / 2;
762 
763     ID3D11Texture2D *texture = nullptr;
764     (void)device->CreateTexture2D(&desc, &subres, &texture);
765     ASSERT_NE(nullptr, texture);
766 
767     // Create the stream
768     const EGLint streamAttributes[] = {
769         EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
770     };
771 
772     EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
773     ASSERT_EGL_SUCCESS();
774 
775     EGLAttrib consumerAttributes[] = {
776         EGL_COLOR_BUFFER_TYPE,
777         EGL_YUV_BUFFER_EXT,
778         EGL_YUV_NUMBER_OF_PLANES_EXT,
779         2,
780         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
781         0,
782         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
783         1,
784         EGL_NONE,
785     };
786 
787     GLuint tex[2];
788     glGenTextures(2, tex);
789     glActiveTexture(GL_TEXTURE0);
790     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
791     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
792     ASSERT_GL_NO_ERROR();
793     glActiveTexture(GL_TEXTURE1);
794     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
795     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
796     ASSERT_GL_NO_ERROR();
797 
798     EGLBoolean result =
799         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
800     ASSERT_EGL_TRUE(result);
801     ASSERT_EGL_SUCCESS();
802 
803     EGLAttrib producerAttributes[] = {
804         EGL_NONE,
805     };
806 
807     result = eglCreateStreamProducerD3DTextureANGLE(display, stream, producerAttributes);
808     ASSERT_EGL_TRUE(result);
809     ASSERT_EGL_SUCCESS();
810 
811     // Insert the frame
812     EGLAttrib frameAttributes[] = {
813         EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
814         0,
815         EGL_NONE,
816     };
817     result = eglStreamPostD3DTextureANGLE(display, stream, (void *)texture, frameAttributes);
818     ASSERT_EGL_TRUE(result);
819     ASSERT_EGL_SUCCESS();
820 
821     EGLint state;
822     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
823     ASSERT_EGL_SUCCESS();
824     ASSERT_EQ(EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR, state);
825 
826     eglStreamConsumerAcquireKHR(display, stream);
827     ASSERT_EGL_SUCCESS();
828 
829     glUseProgram(program);
830     glUniform1i(yUniform, 0);
831     glUniform1i(uvUniform, 1);
832     drawQuad(program, "position", 0.0f);
833     ASSERT_GL_NO_ERROR();
834 
835     eglStreamConsumerReleaseKHR(display, stream);
836     ASSERT_EGL_SUCCESS();
837 
838     eglSwapBuffers(display, window->getSurface());
839     SafeRelease(texture);
840 }
841 
842 // Test P010 texture sampling via EGLStreams
TEST_P(D3D11TextureStreamSamplingTest,P010)843 TEST_P(D3D11TextureStreamSamplingTest, P010)
844 {
845     EGLWindow *window  = getEGLWindow();
846     EGLDisplay display = window->getDisplay();
847     ANGLE_SKIP_TEST_IF(
848         !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture"));
849     ANGLE_SKIP_TEST_IF(!CheckP010TextureSupport(mD3D));
850     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
851 
852     constexpr char kVertShader[] = R"(
853 attribute vec4 aPos;
854 varying vec2 vTexCoord;
855 void main()
856 {
857     gl_Position = aPos;
858     vTexCoord = gl_Position.xy * 0.5 + 0.5;
859 })";
860 
861     const char kFragShader[] = R"(
862 #extension GL_NV_EGL_stream_consumer_external : require
863 precision mediump float;
864 uniform samplerExternalOES uTexY;
865 uniform samplerExternalOES uTexUV;
866 varying vec2 vTexCoord;
867 void main()
868 {
869     gl_FragColor.r = texture2D(uTexY, vTexCoord).r;
870     gl_FragColor.gb = texture2D(uTexUV, vTexCoord).rg;
871     gl_FragColor.a = 1.0;
872 })";
873 
874     ANGLE_GL_PROGRAM(prog, kVertShader, kFragShader);
875     glUseProgram(prog);
876     GLint location = glGetUniformLocation(prog, "uTexY");
877     ASSERT_NE(location, -1);
878     glUniform1i(location, 0);
879     location = glGetUniformLocation(prog, "uTexUV");
880     ASSERT_NE(location, -1);
881     glUniform1i(location, 1);
882 
883     ASSERT_GL_NO_ERROR();
884 
885     GLTexture tex[2];
886     glActiveTexture(GL_TEXTURE0);
887     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
888     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
889     ASSERT_GL_NO_ERROR();
890     glActiveTexture(GL_TEXTURE1);
891     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
892     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
893     ASSERT_GL_NO_ERROR();
894 
895     glActiveTexture(GL_TEXTURE3);  // Set to an unused slot to ensure StreamConsumer picks up
896                                    // the current slot.
897     constexpr EGLAttrib consumerAttributes[] = {
898         EGL_COLOR_BUFFER_TYPE,
899         EGL_YUV_BUFFER_EXT,
900         EGL_YUV_NUMBER_OF_PLANES_EXT,
901         2,
902         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
903         0,
904         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
905         1,
906         EGL_NONE,
907     };
908     EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV(
909         mDisplay, mStream, const_cast<EGLAttrib *>(consumerAttributes));
910     ASSERT_EGL_TRUE(result);
911     ASSERT_EGL_SUCCESS();
912 
913     result = eglCreateStreamProducerD3DTextureANGLE(mDisplay, mStream, nullptr);
914     ASSERT_EGL_TRUE(result);
915     ASSERT_EGL_SUCCESS();
916 
917     // Create and post the d3d11 texture
918 
919     D3D11_TEXTURE2D_DESC desc = {};
920     desc.Width                = 2;
921     desc.Height               = 2;
922     desc.Format               = DXGI_FORMAT_P010;
923     desc.MipLevels            = 1;
924     desc.ArraySize            = 1;
925     desc.SampleDesc.Count     = 1;
926     desc.Usage                = D3D11_USAGE_DEFAULT;
927     desc.BindFlags            = D3D11_BIND_SHADER_RESOURCE;
928 
929     // DXGI_FORMAT_P010:
930     // Width and height must be even.
931     // Direct3D 11 staging resources and initData parameters for this format use
932     // (rowPitch * (height + (height / 2))) bytes.
933     // The first (SysMemPitch * height) bytes are the Y plane, the remaining
934     // (SysMemPitch * (height / 2)) bytes are the UV plane.
935     constexpr uint16_t texData[] = {0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000};
936     D3D11_SUBRESOURCE_DATA subres;
937     subres.pSysMem     = texData;
938     subres.SysMemPitch = 4;
939 
940     ID3D11Texture2D *texture = nullptr;
941     (void)mD3D->CreateTexture2D(&desc, &subres, &texture);
942     ASSERT_NE(nullptr, texture);
943 
944     result = eglStreamPostD3DTextureANGLE(mDisplay, mStream, (void *)texture, nullptr);
945     ASSERT_EGL_TRUE(result);
946     ASSERT_EGL_SUCCESS();
947 
948     // Sample and test
949 
950     result = eglStreamConsumerAcquireKHR(mDisplay, mStream);
951     ASSERT_EGL_TRUE(result);
952     ASSERT_EGL_SUCCESS();
953 
954     drawQuad(prog, "aPos", 0.0);
955     uint32_t pixel;
956     glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
957     ASSERT_EQ(pixel, 0xff605010);
958 
959     glReadPixels(1, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
960     ASSERT_EQ(pixel, 0xff605020);
961 
962     glReadPixels(0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
963     ASSERT_EQ(pixel, 0xff605030);
964 
965     glReadPixels(1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
966     ASSERT_EQ(pixel, 0xff605040);
967 
968     result = eglStreamConsumerReleaseKHR(mDisplay, mStream);
969     ASSERT_EGL_TRUE(result);
970     ASSERT_EGL_SUCCESS();
971 }
972 
973 ANGLE_INSTANTIATE_TEST(EGLStreamTest,
974                        ES2_D3D9(),
975                        ES2_D3D11(),
976                        ES3_D3D11(),
977                        ES2_OPENGL(),
978                        ES3_OPENGL(),
979                        ES2_VULKAN());
980 ANGLE_INSTANTIATE_TEST(D3D11TextureStreamSamplingTest, ES2_D3D11(), ES3_D3D11(), ES31_D3D11());
981 }  // anonymous namespace
982