• 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 <d3d11.h>
13 #include <vector>
14 
15 #include "media/yuvtest.inl"
16 #include "test_utils/ANGLETest.h"
17 #include "test_utils/gl_raii.h"
18 #include "util/EGLWindow.h"
19 #include "util/OSWindow.h"
20 
21 using namespace angle;
22 
23 namespace
24 {
25 
CheckTextureSupport(ID3D11Device * device,DXGI_FORMAT format)26 bool CheckTextureSupport(ID3D11Device *device, DXGI_FORMAT format)
27 {
28     HRESULT result;
29     UINT formatSupport;
30     result = device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
31     if (result == E_FAIL)
32     {
33         return false;
34     }
35     return (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
36 }
37 
CheckNV12TextureSupport(ID3D11Device * device)38 bool CheckNV12TextureSupport(ID3D11Device *device)
39 {
40     return CheckTextureSupport(device, DXGI_FORMAT_NV12);
41 }
42 
CheckP010TextureSupport(ID3D11Device * device)43 bool CheckP010TextureSupport(ID3D11Device *device)
44 {
45     return CheckTextureSupport(device, DXGI_FORMAT_P010);
46 }
47 
48 class EGLStreamTest : public ANGLETest<>
49 {
50   protected:
EGLStreamTest()51     EGLStreamTest()
52     {
53         setWindowWidth(128);
54         setWindowHeight(128);
55         setConfigRedBits(8);
56         setConfigGreenBits(8);
57         setConfigBlueBits(8);
58         setConfigAlphaBits(8);
59         setConfigDepthBits(24);
60     }
61 };
62 
63 // Tests validation of the stream API
TEST_P(EGLStreamTest,StreamValidationTest)64 TEST_P(EGLStreamTest, StreamValidationTest)
65 {
66     EGLWindow *window            = getEGLWindow();
67     EGLDisplay display           = window->getDisplay();
68     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
69     if (strstr(extensionsString, "EGL_KHR_stream") == nullptr)
70     {
71         std::cout << "Stream extension not supported" << std::endl;
72         return;
73     }
74 
75     const EGLint streamAttributesBad[] = {
76         EGL_STREAM_STATE_KHR,
77         0,
78         EGL_NONE,
79         EGL_PRODUCER_FRAME_KHR,
80         0,
81         EGL_NONE,
82         EGL_CONSUMER_FRAME_KHR,
83         0,
84         EGL_NONE,
85         EGL_CONSUMER_LATENCY_USEC_KHR,
86         -1,
87         EGL_NONE,
88         EGL_RED_SIZE,
89         EGL_DONT_CARE,
90         EGL_NONE,
91     };
92 
93     // Validate create stream attributes
94     EGLStreamKHR stream = eglCreateStreamKHR(display, &streamAttributesBad[0]);
95     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
96     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
97 
98     stream = eglCreateStreamKHR(display, &streamAttributesBad[3]);
99     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
100     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
101 
102     stream = eglCreateStreamKHR(display, &streamAttributesBad[6]);
103     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
104     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
105 
106     stream = eglCreateStreamKHR(display, &streamAttributesBad[9]);
107     ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
108     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
109 
110     stream = eglCreateStreamKHR(display, &streamAttributesBad[12]);
111     ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
112     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
113 
114     const EGLint streamAttributes[] = {
115         EGL_CONSUMER_LATENCY_USEC_KHR,
116         0,
117         EGL_NONE,
118     };
119 
120     stream = eglCreateStreamKHR(EGL_NO_DISPLAY, streamAttributes);
121     ASSERT_EGL_ERROR(EGL_BAD_DISPLAY);
122     ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
123 
124     // Create an actual stream
125     stream = eglCreateStreamKHR(display, streamAttributes);
126     ASSERT_EGL_SUCCESS();
127     ASSERT_NE(EGL_NO_STREAM_KHR, stream);
128 
129     // Assert it is in the created state
130     EGLint state;
131     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
132     ASSERT_EGL_SUCCESS();
133     ASSERT_EQ(EGL_STREAM_STATE_CREATED_KHR, state);
134 
135     // Test getting and setting the latency
136     EGLint latency = 10;
137     eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, latency);
138     ASSERT_EGL_SUCCESS();
139     eglQueryStreamKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, &latency);
140     ASSERT_EGL_SUCCESS();
141     ASSERT_EQ(10, latency);
142     eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, -1);
143     ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
144     ASSERT_EQ(10, latency);
145 
146     // Test the 64-bit queries
147     EGLuint64KHR value;
148     eglQueryStreamu64KHR(display, stream, EGL_CONSUMER_FRAME_KHR, &value);
149     ASSERT_EGL_SUCCESS();
150     eglQueryStreamu64KHR(display, stream, EGL_PRODUCER_FRAME_KHR, &value);
151     ASSERT_EGL_SUCCESS();
152 
153     // Destroy the stream
154     eglDestroyStreamKHR(display, stream);
155     ASSERT_EGL_SUCCESS();
156 }
157 
158 // Tests validation of stream consumer gltexture API
TEST_P(EGLStreamTest,StreamConsumerGLTextureValidationTest)159 TEST_P(EGLStreamTest, StreamConsumerGLTextureValidationTest)
160 {
161     EGLWindow *window            = getEGLWindow();
162     EGLDisplay display           = window->getDisplay();
163     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
164     if (strstr(extensionsString, "EGL_KHR_stream_consumer_gltexture") == nullptr)
165     {
166         std::cout << "Stream consumer gltexture extension not supported" << std::endl;
167         return;
168     }
169 
170     const EGLint streamAttributes[] = {
171         EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
172     };
173 
174     EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
175     ASSERT_EGL_SUCCESS();
176 
177     EGLBoolean result = eglStreamConsumerGLTextureExternalKHR(display, stream);
178     ASSERT_EGL_FALSE(result);
179     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
180 
181     GLTexture 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     GLTexture tex[2];
290     glActiveTexture(GL_TEXTURE0);
291     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
292     glActiveTexture(GL_TEXTURE1);
293     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
294 
295     result =
296         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[26]);
297     ASSERT_EGL_FALSE(result);
298     ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
299 
300     result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
301     ASSERT_EGL_TRUE(result);
302     ASSERT_EGL_SUCCESS();
303 
304     EGLint state;
305     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
306     ASSERT_EGL_SUCCESS();
307     ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state);
308 
309     eglDestroyStreamKHR(display, stream);
310     ASSERT_EGL_SUCCESS();
311 }
312 
313 // Tests that deleting a texture invalidates the associated stream
TEST_P(EGLStreamTest,StreamConsumerGLTextureYUVDeletionTest)314 TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVDeletionTest)
315 {
316     EGLWindow *window            = getEGLWindow();
317     EGLDisplay display           = window->getDisplay();
318     const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
319     if (strstr(extensionsString, "EGL_ANGLE_stream_producer_d3d_texture") == nullptr)
320     {
321         std::cout << "Stream producer d3d texture not supported" << std::endl;
322         return;
323     }
324 
325     const EGLint streamAttributes[] = {
326         EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
327     };
328 
329     EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
330     ASSERT_EGL_SUCCESS();
331 
332     EGLAttrib consumerAttributes[] = {
333         EGL_COLOR_BUFFER_TYPE,
334         EGL_YUV_BUFFER_EXT,
335         EGL_YUV_NUMBER_OF_PLANES_EXT,
336         2,
337         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
338         0,
339         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
340         1,
341         EGL_NONE,
342     };
343 
344     // Note: The purpose of this test means that we can't use the RAII GLTexture class
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_GL_FRAMEBUFFER_COMPLETE(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     GLTexture tex[2];
788     glActiveTexture(GL_TEXTURE0);
789     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
790     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
791     ASSERT_GL_NO_ERROR();
792     glActiveTexture(GL_TEXTURE1);
793     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
794     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
795     ASSERT_GL_NO_ERROR();
796 
797     EGLBoolean result =
798         eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
799     ASSERT_EGL_TRUE(result);
800     ASSERT_EGL_SUCCESS();
801 
802     EGLAttrib producerAttributes[] = {
803         EGL_NONE,
804     };
805 
806     result = eglCreateStreamProducerD3DTextureANGLE(display, stream, producerAttributes);
807     ASSERT_EGL_TRUE(result);
808     ASSERT_EGL_SUCCESS();
809 
810     // Insert the frame
811     EGLAttrib frameAttributes[] = {
812         EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
813         0,
814         EGL_NONE,
815     };
816     result = eglStreamPostD3DTextureANGLE(display, stream, (void *)texture, frameAttributes);
817     ASSERT_EGL_TRUE(result);
818     ASSERT_EGL_SUCCESS();
819 
820     EGLint state;
821     eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
822     ASSERT_EGL_SUCCESS();
823     ASSERT_EQ(EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR, state);
824 
825     eglStreamConsumerAcquireKHR(display, stream);
826     ASSERT_EGL_SUCCESS();
827 
828     glUseProgram(program);
829     glUniform1i(yUniform, 0);
830     glUniform1i(uvUniform, 1);
831     drawQuad(program, "position", 0.0f);
832     ASSERT_GL_NO_ERROR();
833 
834     eglStreamConsumerReleaseKHR(display, stream);
835     ASSERT_EGL_SUCCESS();
836 
837     eglSwapBuffers(display, window->getSurface());
838     SafeRelease(texture);
839 }
840 
841 // Test P010 texture sampling via EGLStreams
TEST_P(D3D11TextureStreamSamplingTest,P010)842 TEST_P(D3D11TextureStreamSamplingTest, P010)
843 {
844     EGLWindow *window  = getEGLWindow();
845     EGLDisplay display = window->getDisplay();
846     ANGLE_SKIP_TEST_IF(
847         !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture"));
848     ANGLE_SKIP_TEST_IF(!CheckP010TextureSupport(mD3D));
849     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
850 
851     constexpr char kVertShader[] = R"(
852 attribute vec4 aPos;
853 varying vec2 vTexCoord;
854 void main()
855 {
856     gl_Position = aPos;
857     vTexCoord = gl_Position.xy * 0.5 + 0.5;
858 })";
859 
860     const char kFragShader[] = R"(
861 #extension GL_NV_EGL_stream_consumer_external : require
862 precision mediump float;
863 uniform samplerExternalOES uTexY;
864 uniform samplerExternalOES uTexUV;
865 varying vec2 vTexCoord;
866 void main()
867 {
868     gl_FragColor.r = texture2D(uTexY, vTexCoord).r;
869     gl_FragColor.gb = texture2D(uTexUV, vTexCoord).rg;
870     gl_FragColor.a = 1.0;
871 })";
872 
873     ANGLE_GL_PROGRAM(prog, kVertShader, kFragShader);
874     glUseProgram(prog);
875     GLint location = glGetUniformLocation(prog, "uTexY");
876     ASSERT_NE(location, -1);
877     glUniform1i(location, 0);
878     location = glGetUniformLocation(prog, "uTexUV");
879     ASSERT_NE(location, -1);
880     glUniform1i(location, 1);
881 
882     ASSERT_GL_NO_ERROR();
883 
884     GLTexture tex[2];
885     glActiveTexture(GL_TEXTURE0);
886     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
887     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
888     ASSERT_GL_NO_ERROR();
889     glActiveTexture(GL_TEXTURE1);
890     glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
891     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
892     ASSERT_GL_NO_ERROR();
893 
894     glActiveTexture(GL_TEXTURE3);  // Set to an unused slot to ensure StreamConsumer picks up
895                                    // the current slot.
896     constexpr EGLAttrib consumerAttributes[] = {
897         EGL_COLOR_BUFFER_TYPE,
898         EGL_YUV_BUFFER_EXT,
899         EGL_YUV_NUMBER_OF_PLANES_EXT,
900         2,
901         EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
902         0,
903         EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
904         1,
905         EGL_NONE,
906     };
907     EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV(
908         mDisplay, mStream, const_cast<EGLAttrib *>(consumerAttributes));
909     ASSERT_EGL_TRUE(result);
910     ASSERT_EGL_SUCCESS();
911 
912     result = eglCreateStreamProducerD3DTextureANGLE(mDisplay, mStream, nullptr);
913     ASSERT_EGL_TRUE(result);
914     ASSERT_EGL_SUCCESS();
915 
916     // Create and post the d3d11 texture
917 
918     D3D11_TEXTURE2D_DESC desc = {};
919     desc.Width                = 2;
920     desc.Height               = 2;
921     desc.Format               = DXGI_FORMAT_P010;
922     desc.MipLevels            = 1;
923     desc.ArraySize            = 1;
924     desc.SampleDesc.Count     = 1;
925     desc.Usage                = D3D11_USAGE_DEFAULT;
926     desc.BindFlags            = D3D11_BIND_SHADER_RESOURCE;
927 
928     // DXGI_FORMAT_P010:
929     // Width and height must be even.
930     // Direct3D 11 staging resources and initData parameters for this format use
931     // (rowPitch * (height + (height / 2))) bytes.
932     // The first (SysMemPitch * height) bytes are the Y plane, the remaining
933     // (SysMemPitch * (height / 2)) bytes are the UV plane.
934     constexpr uint16_t texData[] = {0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000};
935     D3D11_SUBRESOURCE_DATA subres;
936     subres.pSysMem     = texData;
937     subres.SysMemPitch = 4;
938 
939     ID3D11Texture2D *texture = nullptr;
940     (void)mD3D->CreateTexture2D(&desc, &subres, &texture);
941     ASSERT_NE(nullptr, texture);
942 
943     result = eglStreamPostD3DTextureANGLE(mDisplay, mStream, (void *)texture, nullptr);
944     ASSERT_EGL_TRUE(result);
945     ASSERT_EGL_SUCCESS();
946 
947     // Sample and test
948 
949     result = eglStreamConsumerAcquireKHR(mDisplay, mStream);
950     ASSERT_EGL_TRUE(result);
951     ASSERT_EGL_SUCCESS();
952 
953     drawQuad(prog, "aPos", 0.0);
954     uint32_t pixel;
955     glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
956     ASSERT_EQ(pixel, 0xff605010);
957 
958     glReadPixels(1, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
959     ASSERT_EQ(pixel, 0xff605020);
960 
961     glReadPixels(0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
962     ASSERT_EQ(pixel, 0xff605030);
963 
964     glReadPixels(1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
965     ASSERT_EQ(pixel, 0xff605040);
966 
967     result = eglStreamConsumerReleaseKHR(mDisplay, mStream);
968     ASSERT_EGL_TRUE(result);
969     ASSERT_EGL_SUCCESS();
970 }
971 
972 ANGLE_INSTANTIATE_TEST(EGLStreamTest,
973                        ES2_D3D9(),
974                        ES2_D3D11(),
975                        ES3_D3D11(),
976                        ES2_OPENGL(),
977                        ES3_OPENGL(),
978                        ES2_VULKAN());
979 ANGLE_INSTANTIATE_TEST(D3D11TextureStreamSamplingTest, ES2_D3D11(), ES3_D3D11(), ES31_D3D11());
980 }  // anonymous namespace
981