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