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