1 //
2 // Copyright 2015 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 // D3DTextureTest:
7 // Tests of the EGL_ANGLE_d3d_texture_client_buffer extension
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 #include <d3d11.h>
13 #include <d3d9.h>
14 #include <dxgiformat.h>
15 #include <windows.h>
16 #include <wrl/client.h>
17
18 #include "util/EGLWindow.h"
19 #include "util/com_utils.h"
20
21 namespace angle
22 {
23
24 class D3DTextureTest : public ANGLETest<>
25 {
26 protected:
D3DTextureTest()27 D3DTextureTest()
28 {
29 setWindowWidth(128);
30 setWindowHeight(128);
31 setConfigRedBits(8);
32 setConfigGreenBits(8);
33 setConfigBlueBits(8);
34 setConfigAlphaBits(8);
35 setConfigDepthBits(24);
36 setConfigStencilBits(8);
37 }
38
testSetUp()39 void testSetUp() override
40 {
41 constexpr char kVS[] =
42 R"(precision highp float;
43 attribute vec4 position;
44 varying vec2 texcoord;
45
46 void main()
47 {
48 gl_Position = position;
49 texcoord = (position.xy * 0.5) + 0.5;
50 texcoord.y = 1.0 - texcoord.y;
51 })";
52
53 constexpr char kTextureFS[] =
54 R"(precision highp float;
55 uniform sampler2D tex;
56 varying vec2 texcoord;
57
58 void main()
59 {
60 gl_FragColor = texture2D(tex, texcoord);
61 })";
62
63 constexpr char kTextureFSNoSampling[] =
64 R"(precision highp float;
65
66 void main()
67 {
68 gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
69 })";
70
71 mTextureProgram = CompileProgram(kVS, kTextureFS);
72 ASSERT_NE(0u, mTextureProgram) << "shader compilation failed.";
73
74 mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
75 ASSERT_NE(-1, mTextureUniformLocation);
76
77 mTextureProgramNoSampling = CompileProgram(kVS, kTextureFSNoSampling);
78 ASSERT_NE(0u, mTextureProgramNoSampling) << "shader compilation failed.";
79
80 mD3D11Module = LoadLibrary(TEXT("d3d11.dll"));
81 ASSERT_NE(nullptr, mD3D11Module);
82
83 PFN_D3D11_CREATE_DEVICE createDeviceFunc = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
84 GetProcAddress(mD3D11Module, "D3D11CreateDevice"));
85
86 EGLWindow *window = getEGLWindow();
87 EGLDisplay display = window->getDisplay();
88 EGLDeviceEXT device = EGL_NO_DEVICE_EXT;
89 if (IsEGLClientExtensionEnabled("EGL_EXT_device_query"))
90 {
91 EGLAttrib result = 0;
92 EXPECT_EGL_TRUE(eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, &result));
93 device = reinterpret_cast<EGLDeviceEXT>(result);
94 }
95
96 ASSERT_NE(EGL_NO_DEVICE_EXT, device);
97
98 if (IsEGLDeviceExtensionEnabled(device, "EGL_ANGLE_device_d3d"))
99 {
100 EGLAttrib result = 0;
101 if (eglQueryDeviceAttribEXT(device, EGL_D3D11_DEVICE_ANGLE, &result))
102 {
103 mD3D11Device = reinterpret_cast<ID3D11Device *>(result);
104 mD3D11Device->AddRef();
105 }
106 else if (eglQueryDeviceAttribEXT(device, EGL_D3D9_DEVICE_ANGLE, &result))
107 {
108 mD3D9Device = reinterpret_cast<IDirect3DDevice9 *>(result);
109 mD3D9Device->AddRef();
110 }
111 }
112 else
113 {
114 ASSERT_TRUE(
115 SUCCEEDED(createDeviceFunc(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr,
116 0, D3D11_SDK_VERSION, &mD3D11Device, nullptr, nullptr)));
117 }
118 }
119
testTearDown()120 void testTearDown() override
121 {
122 glDeleteProgram(mTextureProgram);
123 glDeleteProgram(mTextureProgramNoSampling);
124
125 if (mD3D11Device)
126 {
127 mD3D11Device->Release();
128 mD3D11Device = nullptr;
129 }
130
131 FreeLibrary(mD3D11Module);
132 mD3D11Module = nullptr;
133
134 if (mD3D9Device)
135 {
136 mD3D9Device->Release();
137 mD3D9Device = nullptr;
138 }
139 }
140
createD3D11PBuffer(size_t width,size_t height,UINT sampleCount,UINT sampleQuality,UINT bindFlags,DXGI_FORMAT format,const EGLint * attribs)141 EGLSurface createD3D11PBuffer(size_t width,
142 size_t height,
143 UINT sampleCount,
144 UINT sampleQuality,
145 UINT bindFlags,
146 DXGI_FORMAT format,
147 const EGLint *attribs)
148 {
149 EGLWindow *window = getEGLWindow();
150 EGLDisplay display = window->getDisplay();
151 EGLConfig config = window->getConfig();
152
153 EXPECT_TRUE(mD3D11Device != nullptr);
154 ID3D11Texture2D *texture = nullptr;
155 CD3D11_TEXTURE2D_DESC desc(format, static_cast<UINT>(width), static_cast<UINT>(height), 1,
156 1, bindFlags);
157 desc.SampleDesc.Count = sampleCount;
158 desc.SampleDesc.Quality = sampleQuality;
159 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture)));
160
161 EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
162 texture, config, attribs);
163
164 texture->Release();
165
166 return pbuffer;
167 }
168
createD3D11PBuffer(size_t width,size_t height,EGLint eglTextureFormat,EGLint eglTextureTarget,UINT sampleCount,UINT sampleQuality,UINT bindFlags,DXGI_FORMAT format)169 EGLSurface createD3D11PBuffer(size_t width,
170 size_t height,
171 EGLint eglTextureFormat,
172 EGLint eglTextureTarget,
173 UINT sampleCount,
174 UINT sampleQuality,
175 UINT bindFlags,
176 DXGI_FORMAT format)
177 {
178 EGLint attribs[] = {
179 EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET,
180 eglTextureTarget, EGL_NONE, EGL_NONE,
181 };
182 return createD3D11PBuffer(width, height, sampleCount, sampleQuality, bindFlags, format,
183 attribs);
184 }
185
createPBuffer(size_t width,size_t height,EGLint eglTextureFormat,EGLint eglTextureTarget,UINT sampleCount,UINT sampleQuality)186 EGLSurface createPBuffer(size_t width,
187 size_t height,
188 EGLint eglTextureFormat,
189 EGLint eglTextureTarget,
190 UINT sampleCount,
191 UINT sampleQuality)
192 {
193 if (mD3D11Device)
194 {
195 return createD3D11PBuffer(
196 width, height, eglTextureFormat, eglTextureTarget, sampleCount, sampleQuality,
197 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM);
198 }
199
200 if (mD3D9Device)
201 {
202 EGLWindow *window = getEGLWindow();
203 EGLDisplay display = window->getDisplay();
204 EGLConfig config = window->getConfig();
205
206 EGLint attribs[] = {
207 EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET,
208 eglTextureTarget, EGL_NONE, EGL_NONE,
209 };
210
211 // Multisampled textures are not supported on D3D9.
212 EXPECT_TRUE(sampleCount <= 1);
213 EXPECT_TRUE(sampleQuality == 0);
214
215 IDirect3DTexture9 *texture = nullptr;
216 EXPECT_TRUE(SUCCEEDED(mD3D9Device->CreateTexture(
217 static_cast<UINT>(width), static_cast<UINT>(height), 1, D3DUSAGE_RENDERTARGET,
218 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, nullptr)));
219
220 EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
221 texture, config, attribs);
222
223 texture->Release();
224
225 return pbuffer;
226 }
227 else
228 {
229 return EGL_NO_SURFACE;
230 }
231 }
232
valid() const233 bool valid() const
234 {
235 EGLWindow *window = getEGLWindow();
236 EGLDisplay display = window->getDisplay();
237 if (!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_d3d_texture_client_buffer"))
238 {
239 std::cout << "Test skipped due to missing EGL_ANGLE_d3d_texture_client_buffer"
240 << std::endl;
241 return false;
242 }
243
244 if (!mD3D11Device && !mD3D9Device)
245 {
246 std::cout << "Test skipped due to no D3D devices being available." << std::endl;
247 return false;
248 }
249
250 if (IsWindows() && IsAMD() && IsOpenGL())
251 {
252 std::cout << "Test skipped on Windows AMD OpenGL." << std::endl;
253 return false;
254 }
255
256 if (IsWindows() && IsIntel() && IsOpenGL())
257 {
258 std::cout << "Test skipped on Windows Intel OpenGL." << std::endl;
259 return false;
260 }
261 return true;
262 }
263
testTextureSamplesAs50PercentGreen(GLuint texture)264 void testTextureSamplesAs50PercentGreen(GLuint texture)
265 {
266 GLFramebuffer scratchFbo;
267 glBindFramebuffer(GL_FRAMEBUFFER, scratchFbo);
268 GLTexture scratchTexture;
269 glBindTexture(GL_TEXTURE_2D, scratchTexture);
270 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
271 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, scratchTexture,
272 0);
273
274 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
275 glClear(GL_COLOR_BUFFER_BIT);
276
277 glUseProgram(mTextureProgram);
278 glUniform1i(mTextureUniformLocation, 0);
279 glActiveTexture(GL_TEXTURE0);
280 glBindTexture(GL_TEXTURE_2D, texture);
281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
285
286 drawQuad(mTextureProgram, "position", 0.5f);
287 ASSERT_GL_NO_ERROR();
288
289 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 127u, 0u, 255u), 2);
290 }
291
292 GLuint mTextureProgram;
293 GLuint mTextureProgramNoSampling;
294 GLint mTextureUniformLocation;
295
296 HMODULE mD3D11Module = nullptr;
297 ID3D11Device *mD3D11Device = nullptr;
298
299 IDirect3DDevice9 *mD3D9Device = nullptr;
300 };
301
302 // Test creating pbuffer from textures with several different DXGI formats.
TEST_P(D3DTextureTest,TestD3D11SupportedFormatsSurface)303 TEST_P(D3DTextureTest, TestD3D11SupportedFormatsSurface)
304 {
305 bool srgbSupported = IsGLExtensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;
306 ANGLE_SKIP_TEST_IF(!valid() || !mD3D11Device || !srgbSupported);
307
308 const DXGI_FORMAT formats[] = {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
309 DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB};
310 for (size_t i = 0; i < 4; ++i)
311 {
312 if (formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
313 {
314 if (IsOpenGL())
315 {
316 // This generates an invalid format error when calling wglDXRegisterObjectNV().
317 // Reproducible at least on NVIDIA driver 390.65 on Windows 10.
318 std::cout << "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB subtest skipped: IsOpenGL().\n";
319 continue;
320 }
321 }
322
323 EGLSurface pbuffer = createD3D11PBuffer(32, 32, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0,
324 D3D11_BIND_RENDER_TARGET, formats[i]);
325 ASSERT_EGL_SUCCESS();
326 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
327
328 EGLWindow *window = getEGLWindow();
329 EGLDisplay display = window->getDisplay();
330
331 EGLint colorspace = EGL_NONE;
332 eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace);
333
334 if (formats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ||
335 formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
336 {
337 EXPECT_EQ(EGL_GL_COLORSPACE_SRGB, colorspace);
338 }
339 else
340 {
341 EXPECT_EQ(EGL_GL_COLORSPACE_LINEAR, colorspace);
342 }
343
344 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
345 ASSERT_EGL_SUCCESS();
346 window->makeCurrent();
347 eglDestroySurface(display, pbuffer);
348 }
349 }
350
351 // Test binding a pbuffer created from a D3D texture as a texture image with several different DXGI
352 // formats. The test renders to and samples from the pbuffer.
TEST_P(D3DTextureTest,TestD3D11SupportedFormatsTexture)353 TEST_P(D3DTextureTest, TestD3D11SupportedFormatsTexture)
354 {
355 bool srgb8alpha8TextureAttachmentSupported = getClientMajorVersion() >= 3;
356 ANGLE_SKIP_TEST_IF(!valid() || !mD3D11Device || !srgb8alpha8TextureAttachmentSupported);
357
358 bool srgbWriteControlSupported =
359 IsGLExtensionEnabled("GL_EXT_sRGB_write_control") && !IsOpenGL();
360
361 const DXGI_FORMAT formats[] = {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
362 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
363 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB};
364 for (size_t i = 0; i < 4; ++i)
365 {
366 if (formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
367 {
368 if (IsOpenGL())
369 {
370 // This generates an invalid format error when calling wglDXRegisterObjectNV().
371 // Reproducible at least on NVIDIA driver 390.65 on Windows 10.
372 std::cout << "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB subtest skipped: IsOpenGL().\n";
373 continue;
374 }
375 }
376
377 SCOPED_TRACE(std::string("Test case:") + std::to_string(i));
378 EGLWindow *window = getEGLWindow();
379 EGLDisplay display = window->getDisplay();
380
381 EGLSurface pbuffer =
382 createD3D11PBuffer(32, 32, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0,
383 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, formats[i]);
384 ASSERT_EGL_SUCCESS();
385 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
386
387 EGLint colorspace = EGL_NONE;
388 eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace);
389
390 GLuint texture = 0u;
391 glGenTextures(1, &texture);
392 glBindTexture(GL_TEXTURE_2D, texture);
393 EGLBoolean result = eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER);
394 ASSERT_EGL_SUCCESS();
395 ASSERT_EGL_TRUE(result);
396
397 GLuint fbo = 0u;
398 glGenFramebuffers(1, &fbo);
399 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
400 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
401 glViewport(0, 0, 32, 32);
402
403 GLint colorEncoding = 0;
404 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
405 GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT,
406 &colorEncoding);
407
408 if (formats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ||
409 formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
410 {
411 EXPECT_EQ(EGL_GL_COLORSPACE_SRGB, colorspace);
412 EXPECT_EQ(GL_SRGB_EXT, colorEncoding);
413 }
414 else
415 {
416 EXPECT_EQ(EGL_GL_COLORSPACE_LINEAR, colorspace);
417 EXPECT_EQ(GL_LINEAR, colorEncoding);
418 }
419
420 // Clear the texture with 50% green and check that the color value written is correct.
421 glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
422
423 if (colorEncoding == GL_SRGB_EXT)
424 {
425 glClear(GL_COLOR_BUFFER_BIT);
426 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 188u, 0u, 255u), 2);
427 // Disable SRGB and run the non-sRGB test case.
428 if (srgbWriteControlSupported)
429 glDisable(GL_FRAMEBUFFER_SRGB_EXT);
430 }
431
432 if (colorEncoding == GL_LINEAR || srgbWriteControlSupported)
433 {
434 glClear(GL_COLOR_BUFFER_BIT);
435 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 127u, 0u, 255u), 2);
436 }
437
438 // Draw with the texture to a linear framebuffer and check that the color value written is
439 // correct.
440 testTextureSamplesAs50PercentGreen(texture);
441
442 glBindFramebuffer(GL_FRAMEBUFFER, 0u);
443 glBindTexture(GL_TEXTURE_2D, 0u);
444 glDeleteTextures(1, &texture);
445 glDeleteFramebuffers(1, &fbo);
446 eglDestroySurface(display, pbuffer);
447 }
448 }
449
450 // Test binding a pbuffer created from a D3D texture as a texture image with typeless texture
451 // formats.
TEST_P(D3DTextureTest,TestD3D11TypelessTexture)452 TEST_P(D3DTextureTest, TestD3D11TypelessTexture)
453 {
454 EGLWindow *window = getEGLWindow();
455 EGLDisplay display = window->getDisplay();
456
457 ANGLE_SKIP_TEST_IF(!valid());
458
459 // Typeless formats are optional in the spec and currently only supported on D3D11 backend.
460 ANGLE_SKIP_TEST_IF(!IsD3D11());
461
462 // GL_SRGB8_ALPHA8 texture attachment support is required.
463 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
464
465 const std::array<EGLint, 2> eglGlColorspaces = {EGL_GL_COLORSPACE_LINEAR,
466 EGL_GL_COLORSPACE_SRGB};
467 const std::array<DXGI_FORMAT, 2> dxgiFormats = {DXGI_FORMAT_R8G8B8A8_TYPELESS,
468 DXGI_FORMAT_B8G8R8A8_TYPELESS};
469 for (auto eglGlColorspace : eglGlColorspaces)
470 {
471 for (auto dxgiFormat : dxgiFormats)
472 {
473 SCOPED_TRACE(std::string("Test case:") + std::to_string(eglGlColorspace) + " / " +
474 std::to_string(dxgiFormat));
475
476 EGLint attribs[] = {
477 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
478 EGL_GL_COLORSPACE, eglGlColorspace, EGL_NONE, EGL_NONE,
479 };
480
481 EGLSurface pbuffer = createD3D11PBuffer(
482 32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, dxgiFormat,
483 attribs);
484
485 ASSERT_EGL_SUCCESS();
486 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
487
488 EGLint colorspace = EGL_NONE;
489 eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace);
490
491 GLuint texture = 0u;
492 glGenTextures(1, &texture);
493 glBindTexture(GL_TEXTURE_2D, texture);
494 EGLBoolean result = eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER);
495 ASSERT_EGL_SUCCESS();
496 ASSERT_EGL_TRUE(result);
497
498 GLuint fbo = 0u;
499 glGenFramebuffers(1, &fbo);
500 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
501 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
502 glViewport(0, 0, 32, 32);
503
504 GLint colorEncoding = 0;
505 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
506 GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT,
507 &colorEncoding);
508
509 if (eglGlColorspace == EGL_GL_COLORSPACE_LINEAR)
510 {
511 EXPECT_EQ(EGL_GL_COLORSPACE_LINEAR, colorspace);
512 EXPECT_EQ(GL_LINEAR, colorEncoding);
513 }
514 else
515 {
516 EXPECT_EQ(EGL_GL_COLORSPACE_SRGB, colorspace);
517 EXPECT_EQ(GL_SRGB_EXT, colorEncoding);
518 }
519
520 // Clear the texture with 50% green and check that the color value written is correct.
521 glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
522
523 if (colorEncoding == GL_SRGB_EXT)
524 {
525 glClear(GL_COLOR_BUFFER_BIT);
526 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 188u, 0u, 255u), 2);
527 }
528 if (colorEncoding == GL_LINEAR)
529 {
530 glClear(GL_COLOR_BUFFER_BIT);
531 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 127u, 0u, 255u), 2);
532 }
533
534 // Draw with the texture to a linear framebuffer and check that the color value written
535 // is correct.
536 testTextureSamplesAs50PercentGreen(texture);
537
538 glBindFramebuffer(GL_FRAMEBUFFER, 0u);
539 glBindTexture(GL_TEXTURE_2D, 0u);
540 glDeleteTextures(1, &texture);
541 glDeleteFramebuffers(1, &fbo);
542 eglDestroySurface(display, pbuffer);
543 }
544 }
545 }
546
547 class D3DTextureTestES3 : public D3DTextureTest
548 {
549 protected:
D3DTextureTestES3()550 D3DTextureTestES3() : D3DTextureTest() {}
551 };
552
553 // Test swizzling a pbuffer created from a D3D texture as a texture image with typeless texture
554 // formats.
TEST_P(D3DTextureTestES3,TestD3D11TypelessTextureSwizzle)555 TEST_P(D3DTextureTestES3, TestD3D11TypelessTextureSwizzle)
556 {
557 EGLWindow *window = getEGLWindow();
558 EGLDisplay display = window->getDisplay();
559
560 ANGLE_SKIP_TEST_IF(!valid());
561
562 // Typeless formats are optional in the spec and currently only supported on D3D11 backend.
563 ANGLE_SKIP_TEST_IF(!IsD3D11());
564
565 const std::array<EGLint, 2> eglGlColorspaces = {EGL_GL_COLORSPACE_LINEAR,
566 EGL_GL_COLORSPACE_SRGB};
567 const std::array<DXGI_FORMAT, 2> dxgiFormats = {DXGI_FORMAT_R8G8B8A8_TYPELESS,
568 DXGI_FORMAT_B8G8R8A8_TYPELESS};
569 for (auto eglGlColorspace : eglGlColorspaces)
570 {
571 for (auto dxgiFormat : dxgiFormats)
572 {
573 SCOPED_TRACE(std::string("Test case:") + std::to_string(eglGlColorspace) + " / " +
574 std::to_string(dxgiFormat));
575
576 EGLint attribs[] = {
577 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
578 EGL_GL_COLORSPACE, eglGlColorspace, EGL_NONE, EGL_NONE,
579 };
580
581 EGLSurface pbuffer = createD3D11PBuffer(
582 32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, dxgiFormat,
583 attribs);
584
585 ASSERT_EGL_SUCCESS();
586 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
587
588 EGLint colorspace = EGL_NONE;
589 eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace);
590
591 GLuint texture = 0u;
592 glGenTextures(1, &texture);
593 glBindTexture(GL_TEXTURE_2D, texture);
594 EGLBoolean result = eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER);
595 ASSERT_EGL_SUCCESS();
596 ASSERT_EGL_TRUE(result);
597
598 GLuint fbo = 0u;
599 glGenFramebuffers(1, &fbo);
600 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
601 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
602 glViewport(0, 0, 32, 32);
603
604 GLint colorEncoding = 0;
605 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
606 GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT,
607 &colorEncoding);
608
609 // Clear the texture with 50% blue and check that the color value written is correct.
610 glClearColor(0.0f, 0.0f, 0.5f, 1.0f);
611
612 if (colorEncoding == GL_SRGB_EXT)
613 {
614 glClear(GL_COLOR_BUFFER_BIT);
615 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 0u, 188u, 255u), 2);
616 }
617 if (colorEncoding == GL_LINEAR)
618 {
619 glClear(GL_COLOR_BUFFER_BIT);
620 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 0u, 127u, 255u), 2);
621 }
622
623 // Swizzle the green channel to be sampled from the blue channel of the texture and vice
624 // versa.
625 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE);
626 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_GREEN);
627 ASSERT_GL_NO_ERROR();
628
629 // Draw with the texture to a linear framebuffer and check that the color value written
630 // is correct.
631 testTextureSamplesAs50PercentGreen(texture);
632
633 glBindFramebuffer(GL_FRAMEBUFFER, 0u);
634 glBindTexture(GL_TEXTURE_2D, 0u);
635 glDeleteTextures(1, &texture);
636 glDeleteFramebuffers(1, &fbo);
637 eglDestroySurface(display, pbuffer);
638 }
639 }
640 }
641
642 // Test that EGL_GL_COLORSPACE attrib is not allowed for typed D3D textures.
TEST_P(D3DTextureTest,GlColorspaceNotAllowedForTypedD3DTexture)643 TEST_P(D3DTextureTest, GlColorspaceNotAllowedForTypedD3DTexture)
644 {
645 ANGLE_SKIP_TEST_IF(!valid());
646
647 // D3D11 device is required to be able to create the texture.
648 ANGLE_SKIP_TEST_IF(!mD3D11Device);
649
650 // SRGB support is required.
651 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3);
652
653 EGLint attribsExplicitColorspace[] = {
654 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
655 EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, EGL_NONE, EGL_NONE,
656 };
657 EGLSurface pbuffer =
658 createD3D11PBuffer(32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
659 DXGI_FORMAT_R8G8B8A8_UNORM, attribsExplicitColorspace);
660
661 ASSERT_EGL_ERROR(EGL_BAD_MATCH);
662 ASSERT_EQ(EGL_NO_SURFACE, pbuffer);
663 }
664
665 // Test that trying to create a pbuffer from a typeless texture fails as expected on the backends
666 // where they are known not to be supported.
TEST_P(D3DTextureTest,TypelessD3DTextureNotSupported)667 TEST_P(D3DTextureTest, TypelessD3DTextureNotSupported)
668 {
669 ANGLE_SKIP_TEST_IF(!valid());
670
671 // D3D11 device is required to be able to create the texture.
672 ANGLE_SKIP_TEST_IF(!mD3D11Device);
673
674 // Currently typeless textures are supported on the D3D11 backend. We're testing the backends
675 // where there is no support.
676 ANGLE_SKIP_TEST_IF(IsD3D11());
677
678 // SRGB support is required.
679 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3);
680
681 EGLint attribs[] = {
682 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET,
683 EGL_TEXTURE_2D, EGL_NONE, EGL_NONE,
684 };
685 EGLSurface pbuffer =
686 createD3D11PBuffer(32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
687 DXGI_FORMAT_R8G8B8A8_TYPELESS, attribs);
688 ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
689 ASSERT_EQ(EGL_NO_SURFACE, pbuffer);
690 }
691
692 // Test creating a pbuffer with unnecessary EGL_WIDTH and EGL_HEIGHT attributes because that's what
693 // Chromium does. This is a regression test for crbug.com/794086
TEST_P(D3DTextureTest,UnnecessaryWidthHeightAttributes)694 TEST_P(D3DTextureTest, UnnecessaryWidthHeightAttributes)
695 {
696 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
697 ASSERT_TRUE(mD3D11Device != nullptr);
698 ID3D11Texture2D *texture = nullptr;
699 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET);
700 desc.SampleDesc.Count = 1;
701 desc.SampleDesc.Quality = 0;
702 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture)));
703
704 EGLint attribs[] = {
705 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
706 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
707 EGL_WIDTH, 1,
708 EGL_HEIGHT, 1,
709 EGL_NONE, EGL_NONE,
710 };
711
712 EGLWindow *window = getEGLWindow();
713 EGLDisplay display = window->getDisplay();
714 EGLConfig config = window->getConfig();
715
716 EGLSurface pbuffer =
717 eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, texture, config, attribs);
718
719 ASSERT_EGL_SUCCESS();
720 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
721
722 texture->Release();
723
724 // Make current with fixture EGL to ensure the Surface can be released immediately.
725 getEGLWindow()->makeCurrent();
726 eglDestroySurface(display, pbuffer);
727 }
728
729 // Test creating a pbuffer from a d3d surface and clearing it
TEST_P(D3DTextureTest,Clear)730 TEST_P(D3DTextureTest, Clear)
731 {
732 if (!valid())
733 {
734 return;
735 }
736
737 EGLWindow *window = getEGLWindow();
738 EGLDisplay display = window->getDisplay();
739
740 const size_t bufferSize = 32;
741
742 EGLSurface pbuffer =
743 createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 1, 0);
744 ASSERT_EGL_SUCCESS();
745 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
746
747 // Apply the Pbuffer and clear it to purple and verify
748 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
749 ASSERT_EGL_SUCCESS();
750
751 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
752 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
753 glClear(GL_COLOR_BUFFER_BIT);
754 ASSERT_GL_NO_ERROR();
755
756 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
757 255, 255);
758
759 // Make current with fixture EGL to ensure the Surface can be released immediately.
760 getEGLWindow()->makeCurrent();
761 eglDestroySurface(display, pbuffer);
762 }
763
764 // Test creating a pbuffer with a D3D texture and depth stencil bits in the EGL config creates keeps
765 // its depth stencil buffer
TEST_P(D3DTextureTest,DepthStencil)766 TEST_P(D3DTextureTest, DepthStencil)
767 {
768 if (!valid())
769 {
770 return;
771 }
772
773 EGLWindow *window = getEGLWindow();
774 EGLDisplay display = window->getDisplay();
775
776 const size_t bufferSize = 32;
777
778 EGLSurface pbuffer =
779 createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 1, 0);
780 ASSERT_EGL_SUCCESS();
781 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
782
783 // Apply the Pbuffer and clear it to purple and verify
784 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
785 ASSERT_EGL_SUCCESS();
786
787 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
788 glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
789 glClearDepthf(0.5f);
790 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
791 ASSERT_GL_NO_ERROR();
792
793 glEnable(GL_DEPTH_TEST);
794 glDepthMask(GL_FALSE);
795
796 glUseProgram(mTextureProgram);
797 glUniform1i(mTextureUniformLocation, 0);
798
799 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
800
801 // Draw a quad that will fail the depth test and verify that the buffer is unchanged
802 drawQuad(mTextureProgram, "position", 1.0f);
803 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
804 GLColor::cyan);
805
806 // Draw a quad that will pass the depth test and verify that the buffer is green
807 drawQuad(mTextureProgram, "position", -1.0f);
808 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
809 GLColor::green);
810
811 // Make current with fixture EGL to ensure the Surface can be released immediately.
812 getEGLWindow()->makeCurrent();
813 eglDestroySurface(display, pbuffer);
814 }
815
816 // Test creating a pbuffer from a d3d surface and binding it to a texture
TEST_P(D3DTextureTest,BindTexImage)817 TEST_P(D3DTextureTest, BindTexImage)
818 {
819 if (!valid())
820 {
821 return;
822 }
823
824 EGLWindow *window = getEGLWindow();
825 EGLDisplay display = window->getDisplay();
826
827 const size_t bufferSize = 32;
828
829 EGLSurface pbuffer =
830 createPBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0);
831 ASSERT_EGL_SUCCESS();
832 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
833
834 // Apply the Pbuffer and clear it to purple
835 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
836 ASSERT_EGL_SUCCESS();
837
838 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
839 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
840 glClear(GL_COLOR_BUFFER_BIT);
841 ASSERT_GL_NO_ERROR();
842
843 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
844 255, 255);
845
846 // Apply the window surface
847 eglMakeCurrent(display, window->getSurface(), window->getSurface(), window->getContext());
848
849 // Create a texture and bind the Pbuffer to it
850 GLuint texture = 0;
851 glGenTextures(1, &texture);
852 glBindTexture(GL_TEXTURE_2D, texture);
853 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
854 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
855 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
856 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
857 EXPECT_GL_NO_ERROR();
858
859 eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER);
860 glViewport(0, 0, getWindowWidth(), getWindowHeight());
861 ASSERT_EGL_SUCCESS();
862
863 // Draw a quad and verify that it is purple
864 glUseProgram(mTextureProgram);
865 glUniform1i(mTextureUniformLocation, 0);
866
867 drawQuad(mTextureProgram, "position", 0.5f);
868 EXPECT_GL_NO_ERROR();
869
870 // Unbind the texture
871 eglReleaseTexImage(display, pbuffer, EGL_BACK_BUFFER);
872 ASSERT_EGL_SUCCESS();
873
874 // Verify that purple was drawn
875 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
876
877 glDeleteTextures(1, &texture);
878
879 // Make current with fixture EGL to ensure the Surface can be released immediately.
880 getEGLWindow()->makeCurrent();
881 eglDestroySurface(display, pbuffer);
882 }
883
884 // Verify that creating a pbuffer with a multisampled texture will fail on a non-multisampled
885 // window.
TEST_P(D3DTextureTest,CheckSampleMismatch)886 TEST_P(D3DTextureTest, CheckSampleMismatch)
887 {
888 if (!valid())
889 {
890 return;
891 }
892
893 // Multisampling is not supported on D3D9 or OpenGL.
894 ANGLE_SKIP_TEST_IF(IsD3D9() || IsOpenGL());
895
896 constexpr size_t bufferSize = 32;
897
898 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 2,
899 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
900 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
901 EXPECT_EQ(pbuffer, nullptr);
902 }
903
904 // Tests what happens when we make a PBuffer that isn't shader-readable.
TEST_P(D3DTextureTest,NonReadablePBuffer)905 TEST_P(D3DTextureTest, NonReadablePBuffer)
906 {
907 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
908
909 constexpr size_t bufferSize = 32;
910
911 EGLSurface pbuffer =
912 createD3D11PBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0,
913 D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM);
914
915 ASSERT_EGL_SUCCESS();
916 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
917
918 EGLWindow *window = getEGLWindow();
919 EGLDisplay display = window->getDisplay();
920
921 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
922 ASSERT_EGL_SUCCESS();
923
924 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
925
926 // Clear to green.
927 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
928 glClear(GL_COLOR_BUFFER_BIT);
929 ASSERT_GL_NO_ERROR();
930 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
931
932 // Copy the green color to a texture.
933 GLTexture tex;
934 glBindTexture(GL_TEXTURE_2D, tex);
935 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
936 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
937 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, bufferSize, bufferSize, 0);
938 ASSERT_GL_NO_ERROR();
939
940 // Clear to red.
941 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
942 glClear(GL_COLOR_BUFFER_BIT);
943 ASSERT_GL_NO_ERROR();
944 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
945
946 // Draw with the texture and expect green.
947 draw2DTexturedQuad(0.5f, 1.0f, false);
948 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
949
950 // Make current with fixture EGL to ensure the Surface can be released immediately.
951 getEGLWindow()->makeCurrent();
952 eglDestroySurface(display, pbuffer);
953 }
954
955 class D3DTextureTestMS : public D3DTextureTest
956 {
957 protected:
D3DTextureTestMS()958 D3DTextureTestMS() : D3DTextureTest()
959 {
960 setSamples(4);
961 setMultisampleEnabled(true);
962 }
963 };
964
965 // Test creating a pbuffer from a multisampled d3d surface and clearing it.
TEST_P(D3DTextureTestMS,Clear)966 TEST_P(D3DTextureTestMS, Clear)
967 {
968 EGLWindow *window = getEGLWindow();
969 EGLDisplay display = window->getDisplay();
970
971 constexpr size_t bufferSize = 32;
972 constexpr UINT testpoint = bufferSize / 2;
973
974 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4,
975 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
976 ASSERT_EGL_SUCCESS();
977 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
978
979 // Apply the Pbuffer and clear it to magenta and verify
980 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
981 ASSERT_EGL_SUCCESS();
982
983 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
984 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
985 glClear(GL_COLOR_BUFFER_BIT);
986 ASSERT_GL_NO_ERROR();
987 EXPECT_PIXEL_COLOR_EQ(testpoint, testpoint, GLColor::magenta);
988
989 // Make current with fixture EGL to ensure the Surface can be released immediately.
990 getEGLWindow()->makeCurrent();
991 eglDestroySurface(display, pbuffer);
992 }
993
994 // Test creating a pbuffer from a multisampled d3d surface and drawing with a program.
TEST_P(D3DTextureTestMS,DrawProgram)995 TEST_P(D3DTextureTestMS, DrawProgram)
996 {
997 EGLWindow *window = getEGLWindow();
998 EGLDisplay display = window->getDisplay();
999
1000 constexpr size_t bufferSize = 32;
1001
1002 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4,
1003 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
1004 ASSERT_EGL_SUCCESS();
1005 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
1006
1007 // Apply the Pbuffer and clear it to magenta
1008 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
1009 ASSERT_EGL_SUCCESS();
1010
1011 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1012 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
1013 glClear(GL_COLOR_BUFFER_BIT);
1014 ASSERT_GL_NO_ERROR();
1015
1016 constexpr GLint testPoint = bufferSize / 2;
1017 EXPECT_PIXEL_COLOR_EQ(testPoint, testPoint, GLColor::magenta);
1018
1019 // Apply the window surface
1020 eglMakeCurrent(display, window->getSurface(), window->getSurface(), window->getContext());
1021 ASSERT_EGL_SUCCESS();
1022
1023 glViewport(0, 0, getWindowWidth(), getWindowHeight());
1024 ASSERT_EGL_SUCCESS();
1025
1026 // Draw a quad and verify that it is magenta
1027 glUseProgram(mTextureProgramNoSampling);
1028 EXPECT_GL_NO_ERROR();
1029
1030 drawQuad(mTextureProgramNoSampling, "position", 0.5f);
1031 EXPECT_GL_NO_ERROR();
1032
1033 // Verify that magenta was drawn
1034 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::magenta);
1035
1036 // Make current with fixture EGL to ensure the Surface can be released immediately.
1037 getEGLWindow()->makeCurrent();
1038 eglDestroySurface(display, pbuffer);
1039 }
1040
1041 // Test for failure when creating a pbuffer from a multisampled d3d surface to bind to a texture.
TEST_P(D3DTextureTestMS,BindTexture)1042 TEST_P(D3DTextureTestMS, BindTexture)
1043 {
1044 constexpr size_t bufferSize = 32;
1045
1046 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 4,
1047 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
1048
1049 EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
1050 EXPECT_EQ(pbuffer, nullptr);
1051 }
1052
1053 // Verify that creating a pbuffer from a multisampled texture with a multisampled window will fail
1054 // when the sample counts do not match.
TEST_P(D3DTextureTestMS,CheckSampleMismatch)1055 TEST_P(D3DTextureTestMS, CheckSampleMismatch)
1056 {
1057 constexpr size_t bufferSize = 32;
1058
1059 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 2,
1060 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
1061
1062 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
1063 EXPECT_EQ(pbuffer, nullptr);
1064 }
1065
1066 // Test creating a pbuffer with a D3D texture and depth stencil bits in the EGL config creates keeps
1067 // its depth stencil buffer
TEST_P(D3DTextureTestMS,DepthStencil)1068 TEST_P(D3DTextureTestMS, DepthStencil)
1069 {
1070 EGLWindow *window = getEGLWindow();
1071 EGLDisplay display = window->getDisplay();
1072
1073 const size_t bufferSize = 32;
1074
1075 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4,
1076 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
1077 ASSERT_EGL_SUCCESS();
1078 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
1079
1080 // Apply the Pbuffer and clear it to purple and verify
1081 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
1082 ASSERT_EGL_SUCCESS();
1083
1084 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1085 glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
1086 glClearDepthf(0.5f);
1087 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1088 ASSERT_GL_NO_ERROR();
1089
1090 glEnable(GL_DEPTH_TEST);
1091 glDepthMask(GL_FALSE);
1092
1093 glUseProgram(mTextureProgram);
1094 glUniform1i(mTextureUniformLocation, 0);
1095
1096 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1097
1098 // Draw a quad that will fail the depth test and verify that the buffer is unchanged
1099 drawQuad(mTextureProgram, "position", 1.0f);
1100 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1101 GLColor::cyan);
1102
1103 // Draw a quad that will pass the depth test and verify that the buffer is green
1104 drawQuad(mTextureProgram, "position", -1.0f);
1105 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1106 GLColor::green);
1107
1108 // Make current with fixture EGL to ensure the Surface can be released immediately.
1109 getEGLWindow()->makeCurrent();
1110 eglDestroySurface(display, pbuffer);
1111 }
1112
1113 // Test copyTexImage2D with a multisampled resource
TEST_P(D3DTextureTestMS,CopyTexImage2DTest)1114 TEST_P(D3DTextureTestMS, CopyTexImage2DTest)
1115 {
1116 EGLWindow *window = getEGLWindow();
1117 EGLDisplay display = window->getDisplay();
1118
1119 constexpr size_t bufferSize = 32;
1120
1121 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4,
1122 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
1123 ASSERT_EGL_SUCCESS();
1124 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
1125
1126 // Apply the Pbuffer and clear it to magenta and verify
1127 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
1128 ASSERT_EGL_SUCCESS();
1129
1130 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1131 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
1132 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1133 ASSERT_GL_NO_ERROR();
1134
1135 glUseProgram(mTextureProgram);
1136 glUniform1i(mTextureUniformLocation, 0);
1137
1138 // Specify a 2D texture and set it to green
1139 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1140
1141 // Copy from the multisampled framebuffer to the 2D texture
1142 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
1143
1144 // Draw a quad and verify the color is magenta, not green
1145 drawQuad(mTextureProgram, "position", 1.0f);
1146 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1147 GLColor::magenta);
1148 ASSERT_GL_NO_ERROR();
1149
1150 // Make current with fixture EGL to ensure the Surface can be released immediately.
1151 getEGLWindow()->makeCurrent();
1152 eglDestroySurface(display, pbuffer);
1153 }
1154
1155 // Test copyTexSubImage2D with a multisampled resource
TEST_P(D3DTextureTestMS,CopyTexSubImage2DTest)1156 TEST_P(D3DTextureTestMS, CopyTexSubImage2DTest)
1157 {
1158 EGLWindow *window = getEGLWindow();
1159 EGLDisplay display = window->getDisplay();
1160
1161 constexpr size_t bufferSize = 32;
1162
1163 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4,
1164 static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN));
1165 ASSERT_EGL_SUCCESS();
1166 ASSERT_NE(EGL_NO_SURFACE, pbuffer);
1167
1168 // Apply the Pbuffer and clear it to magenta and verify
1169 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
1170 ASSERT_EGL_SUCCESS();
1171
1172 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1173 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
1174 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1175 ASSERT_GL_NO_ERROR();
1176
1177 glUseProgram(mTextureProgram);
1178 glUniform1i(mTextureUniformLocation, 0);
1179
1180 // Specify a 2D texture and set it to green
1181 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1182
1183 // Copy from the multisampled framebuffer to the 2D texture
1184 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
1185
1186 // Draw a quad and verify the color is magenta, not green
1187 drawQuad(mTextureProgram, "position", 1.0f);
1188 EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1189 GLColor::magenta);
1190 ASSERT_GL_NO_ERROR();
1191
1192 // Make current with fixture EGL to ensure the Surface can be released immediately.
1193 getEGLWindow()->makeCurrent();
1194 eglDestroySurface(display, pbuffer);
1195 }
1196
1197 class D3DTextureClearTest : public D3DTextureTest
1198 {
1199 protected:
D3DTextureClearTest()1200 D3DTextureClearTest() : D3DTextureTest() {}
1201
RunClearTest(DXGI_FORMAT format)1202 void RunClearTest(DXGI_FORMAT format)
1203 {
1204 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1205
1206 EGLWindow *window = getEGLWindow();
1207 EGLDisplay display = window->getDisplay();
1208
1209 window->makeCurrent();
1210
1211 const UINT bufferSize = 32;
1212 EXPECT_TRUE(mD3D11Device != nullptr);
1213 ID3D11Texture2D *d3d11Texture = nullptr;
1214 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
1215 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1216 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1217
1218 // Can use unsized formats for all cases, but use sized ones to match Chromium.
1219 EGLint internalFormat = GL_NONE;
1220 switch (format)
1221 {
1222 case DXGI_FORMAT_R8G8B8A8_UNORM:
1223 case DXGI_FORMAT_R16G16B16A16_FLOAT:
1224 internalFormat = GL_RGBA;
1225 break;
1226 case DXGI_FORMAT_B8G8R8A8_UNORM:
1227 internalFormat = GL_BGRA_EXT;
1228 break;
1229 case DXGI_FORMAT_R8_UNORM:
1230 internalFormat = GL_RED_EXT;
1231 break;
1232 case DXGI_FORMAT_R8G8_UNORM:
1233 internalFormat = GL_RG_EXT;
1234 break;
1235 case DXGI_FORMAT_R10G10B10A2_UNORM:
1236 internalFormat = GL_RGB10_A2_EXT;
1237 break;
1238 case DXGI_FORMAT_R16_UNORM:
1239 internalFormat = GL_R16_EXT;
1240 break;
1241 case DXGI_FORMAT_R16G16_UNORM:
1242 internalFormat = GL_RG16_EXT;
1243 break;
1244 default:
1245 ASSERT_TRUE(false);
1246 break;
1247 }
1248
1249 const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, internalFormat, EGL_NONE};
1250
1251 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1252 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1253 ASSERT_EGL_SUCCESS();
1254 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1255
1256 GLuint texture;
1257 glGenTextures(1, &texture);
1258 glBindTexture(GL_TEXTURE_2D, texture);
1259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1263 ASSERT_GL_NO_ERROR();
1264
1265 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1266 ASSERT_GL_NO_ERROR();
1267
1268 GLuint fbo;
1269 glGenFramebuffers(1, &fbo);
1270 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1271 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1272 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1273 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1274 ASSERT_GL_NO_ERROR();
1275
1276 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1277 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
1278 glClear(GL_COLOR_BUFFER_BIT);
1279 ASSERT_GL_NO_ERROR();
1280
1281 if (format == DXGI_FORMAT_R16G16B16A16_FLOAT)
1282 {
1283 EXPECT_PIXEL_32F_EQ(static_cast<GLint>(bufferSize) / 2,
1284 static_cast<GLint>(bufferSize) / 2, 1.0f, 1.0f, 1.0f, 1.0f);
1285 }
1286 else if (format == DXGI_FORMAT_R16_UNORM)
1287 {
1288 EXPECT_PIXEL_16_NEAR(static_cast<GLint>(bufferSize) / 2,
1289 static_cast<GLint>(bufferSize) / 2, 65535, 0, 0, 65535, 0);
1290 }
1291 else if (format == DXGI_FORMAT_R16G16_UNORM)
1292 {
1293 EXPECT_PIXEL_16_NEAR(static_cast<GLint>(bufferSize) / 2,
1294 static_cast<GLint>(bufferSize) / 2, 65535, 65535, 0, 65535, 0);
1295 }
1296 else
1297 {
1298 GLuint readColor[4] = {0, 0, 0, 255};
1299 switch (internalFormat)
1300 {
1301 case GL_RGBA:
1302 case GL_BGRA_EXT:
1303 case GL_RGB10_A2_EXT:
1304 readColor[0] = readColor[1] = readColor[2] = 255;
1305 break;
1306 case GL_RG_EXT:
1307 readColor[0] = readColor[1] = 255;
1308 break;
1309 case GL_RED_EXT:
1310 readColor[0] = 255;
1311 break;
1312 }
1313 // Read back as GL_UNSIGNED_BYTE even though the texture might have more than 8bpc.
1314 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1315 readColor[0], readColor[1], readColor[2], readColor[3]);
1316 }
1317
1318 glDeleteFramebuffers(1, &fbo);
1319 glDeleteTextures(1, &texture);
1320 eglDestroyImageKHR(display, image);
1321
1322 d3d11Texture->Release();
1323 }
1324 };
1325
TEST_P(D3DTextureClearTest,ClearRGBA8)1326 TEST_P(D3DTextureClearTest, ClearRGBA8)
1327 {
1328 RunClearTest(DXGI_FORMAT_R8G8B8A8_UNORM);
1329 }
1330
TEST_P(D3DTextureClearTest,ClearBGRA8)1331 TEST_P(D3DTextureClearTest, ClearBGRA8)
1332 {
1333 RunClearTest(DXGI_FORMAT_B8G8R8A8_UNORM);
1334 }
1335
TEST_P(D3DTextureClearTest,ClearR8)1336 TEST_P(D3DTextureClearTest, ClearR8)
1337 {
1338 RunClearTest(DXGI_FORMAT_R8_UNORM);
1339 }
1340
TEST_P(D3DTextureClearTest,ClearRG8)1341 TEST_P(D3DTextureClearTest, ClearRG8)
1342 {
1343 RunClearTest(DXGI_FORMAT_R8G8_UNORM);
1344 }
1345
TEST_P(D3DTextureClearTest,ClearRGB10A2)1346 TEST_P(D3DTextureClearTest, ClearRGB10A2)
1347 {
1348 RunClearTest(DXGI_FORMAT_R10G10B10A2_UNORM);
1349 }
1350
TEST_P(D3DTextureClearTest,ClearRGBAF16)1351 TEST_P(D3DTextureClearTest, ClearRGBAF16)
1352 {
1353 RunClearTest(DXGI_FORMAT_R16G16B16A16_FLOAT);
1354 }
1355
TEST_P(D3DTextureClearTest,ClearR16)1356 TEST_P(D3DTextureClearTest, ClearR16)
1357 {
1358 RunClearTest(DXGI_FORMAT_R16_UNORM);
1359 }
1360
TEST_P(D3DTextureClearTest,ClearRG16)1361 TEST_P(D3DTextureClearTest, ClearRG16)
1362 {
1363 RunClearTest(DXGI_FORMAT_R16G16_UNORM);
1364 }
1365
TEST_P(D3DTextureTest,NonRenderableTextureImage)1366 TEST_P(D3DTextureTest, NonRenderableTextureImage)
1367 {
1368 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1369
1370 EGLWindow *window = getEGLWindow();
1371 EGLDisplay display = window->getDisplay();
1372
1373 window->makeCurrent();
1374
1375 const UINT bufferSize = 32;
1376 EXPECT_TRUE(mD3D11Device != nullptr);
1377 ID3D11Texture2D *d3d11Texture = nullptr;
1378 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1,
1379 D3D11_BIND_SHADER_RESOURCE);
1380 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1381
1382 const EGLint attribs[] = {EGL_NONE};
1383
1384 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1385 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1386 ASSERT_EGL_SUCCESS();
1387 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1388
1389 GLuint texture;
1390 glGenTextures(1, &texture);
1391 glBindTexture(GL_TEXTURE_2D, texture);
1392 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1393 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1394 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1395 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1396 ASSERT_GL_NO_ERROR();
1397
1398 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1399 ASSERT_GL_NO_ERROR();
1400
1401 GLuint fbo;
1402 glGenFramebuffers(1, &fbo);
1403 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1404 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1405 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1406 static_cast<unsigned>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT));
1407 ASSERT_GL_NO_ERROR();
1408
1409 glDeleteFramebuffers(1, &fbo);
1410 glDeleteTextures(1, &texture);
1411 eglDestroyImageKHR(display, image);
1412
1413 d3d11Texture->Release();
1414 }
1415
TEST_P(D3DTextureTest,RGBEmulationTextureImage)1416 TEST_P(D3DTextureTest, RGBEmulationTextureImage)
1417 {
1418 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1419
1420 EGLWindow *window = getEGLWindow();
1421 EGLDisplay display = window->getDisplay();
1422
1423 window->makeCurrent();
1424
1425 const UINT bufferSize = 32;
1426 EXPECT_TRUE(mD3D11Device != nullptr);
1427 ID3D11Texture2D *d3d11Texture = nullptr;
1428 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1,
1429 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1430 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1431
1432 const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGB, EGL_NONE};
1433
1434 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1435 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1436 ASSERT_EGL_SUCCESS();
1437 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1438
1439 GLuint texture;
1440 glGenTextures(1, &texture);
1441 glBindTexture(GL_TEXTURE_2D, texture);
1442 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1443 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1444 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1445 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1446 ASSERT_GL_NO_ERROR();
1447
1448 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1449 ASSERT_GL_NO_ERROR();
1450
1451 GLuint fbo;
1452 glGenFramebuffers(1, &fbo);
1453 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1454 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1455 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1456 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1457 ASSERT_GL_NO_ERROR();
1458
1459 // Although we are writing 0.5 to the alpha channel it should have the same
1460 // side effects as if alpha were 1.0.
1461 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1462 glClearColor(1.0f, 0.0f, 1.0f, 0.5f);
1463 glClear(GL_COLOR_BUFFER_BIT);
1464 ASSERT_GL_NO_ERROR();
1465 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
1466 255, 255);
1467
1468 GLuint rgbaRbo;
1469 glGenRenderbuffers(1, &rgbaRbo);
1470 glBindRenderbuffer(GL_RENDERBUFFER, rgbaRbo);
1471 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, bufferSize, bufferSize);
1472
1473 GLuint rgbaFbo;
1474 glGenFramebuffers(1, &rgbaFbo);
1475 glBindFramebuffer(GL_FRAMEBUFFER, rgbaFbo);
1476 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rgbaRbo);
1477 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1478 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1479 ASSERT_GL_NO_ERROR();
1480
1481 // BlitFramebuffer from/to RGBA framebuffer fails.
1482 glBindFramebuffer(GL_READ_FRAMEBUFFER, rgbaFbo);
1483 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1484 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1485 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1486 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1487 ASSERT_GL_NO_ERROR();
1488
1489 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
1490 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rgbaFbo);
1491 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1492 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1493 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1494 ASSERT_GL_NO_ERROR();
1495
1496 GLuint rgbRbo;
1497 glGenRenderbuffers(1, &rgbRbo);
1498 glBindRenderbuffer(GL_RENDERBUFFER, rgbRbo);
1499 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, bufferSize, bufferSize);
1500
1501 GLuint rgbFbo;
1502 glGenFramebuffers(1, &rgbFbo);
1503 glBindFramebuffer(GL_FRAMEBUFFER, rgbFbo);
1504 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rgbRbo);
1505 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1506 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1507 ASSERT_GL_NO_ERROR();
1508 glClearColor(1.0f, 0.0f, 1.0f, 0.5f);
1509 glClear(GL_COLOR_BUFFER_BIT);
1510 ASSERT_GL_NO_ERROR();
1511
1512 // Clear texture framebuffer.
1513 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1514 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1515 glClear(GL_COLOR_BUFFER_BIT);
1516 ASSERT_GL_NO_ERROR();
1517 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 0, 0, 0,
1518 255);
1519
1520 // BlitFramebuffer from/to RGB framebuffer succeeds.
1521 glBindFramebuffer(GL_READ_FRAMEBUFFER, rgbFbo);
1522 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1523 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1524 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1525 ASSERT_GL_NO_ERROR();
1526 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
1527 255, 255);
1528
1529 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1530 glClear(GL_COLOR_BUFFER_BIT);
1531 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
1532 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rgbFbo);
1533 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1534 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1535 ASSERT_GL_NO_ERROR();
1536 glBindFramebuffer(GL_FRAMEBUFFER, rgbFbo);
1537 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 0, 0, 0,
1538 255);
1539
1540 glDeleteFramebuffers(1, &rgbFbo);
1541 glDeleteRenderbuffers(1, &rgbRbo);
1542 glDeleteFramebuffers(1, &rgbaFbo);
1543 glDeleteRenderbuffers(1, &rgbaRbo);
1544 glDeleteFramebuffers(1, &fbo);
1545 glDeleteTextures(1, &texture);
1546 eglDestroyImageKHR(display, image);
1547
1548 d3d11Texture->Release();
1549 }
1550
TEST_P(D3DTextureTest,TextureArray)1551 TEST_P(D3DTextureTest, TextureArray)
1552 {
1553 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1554
1555 EGLWindow *window = getEGLWindow();
1556 EGLDisplay display = window->getDisplay();
1557
1558 window->makeCurrent();
1559
1560 const UINT bufferSize = 32;
1561 const UINT arraySize = 4;
1562
1563 ID3D11Texture2D *d3d11Texture = nullptr;
1564 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, arraySize, 1,
1565 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1566 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1567
1568 const unsigned char kRFill = 0x12;
1569 const unsigned char kGFill = 0x23;
1570 const unsigned char kBFill = 0x34;
1571 const unsigned char kAFill = 0x45;
1572
1573 std::vector<unsigned char> imageData(bufferSize * bufferSize * 4, 0);
1574 for (size_t i = 0; i < imageData.size(); i += 4)
1575 {
1576 imageData[i] = kRFill;
1577 imageData[i + 1] = kGFill;
1578 imageData[i + 2] = kBFill;
1579 imageData[i + 3] = kAFill;
1580 }
1581
1582 ID3D11DeviceContext *context = nullptr;
1583 mD3D11Device->GetImmediateContext(&context);
1584 ASSERT_NE(context, nullptr);
1585
1586 D3D11_BOX dstBox = {0, 0, 0, bufferSize, bufferSize, 1};
1587 context->UpdateSubresource(d3d11Texture, arraySize - 1, &dstBox, imageData.data(),
1588 bufferSize * 4, imageData.size());
1589
1590 const EGLint attribs[] = {EGL_D3D11_TEXTURE_ARRAY_SLICE_ANGLE, arraySize - 1, EGL_NONE};
1591 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1592 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1593 ASSERT_EGL_SUCCESS();
1594 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1595
1596 GLuint texture;
1597 glGenTextures(1, &texture);
1598 glBindTexture(GL_TEXTURE_2D, texture);
1599 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1600 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1602 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1603 ASSERT_GL_NO_ERROR();
1604
1605 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1606 ASSERT_GL_NO_ERROR();
1607
1608 GLuint fbo;
1609 glGenFramebuffers(1, &fbo);
1610 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1611 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1612 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1613 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1614 ASSERT_GL_NO_ERROR();
1615
1616 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, kRFill,
1617 kGFill, kBFill, kAFill);
1618
1619 glDeleteFramebuffers(1, &fbo);
1620 glDeleteTextures(1, &texture);
1621 eglDestroyImageKHR(display, image);
1622
1623 d3d11Texture->Release();
1624 }
1625
1626 class D3DTextureYUVTest : public D3DTextureTest
1627 {
1628 protected:
CreateAndBindImageToTexture(EGLDisplay display,ID3D11Texture2D * d3d11Texture,EGLint plane,GLenum internalFormat,GLenum target,EGLImage * image,GLuint * texture)1629 void CreateAndBindImageToTexture(EGLDisplay display,
1630 ID3D11Texture2D *d3d11Texture,
1631 EGLint plane,
1632 GLenum internalFormat,
1633 GLenum target,
1634 EGLImage *image,
1635 GLuint *texture)
1636 {
1637 const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE,
1638 static_cast<EGLint>(internalFormat),
1639 EGL_D3D11_TEXTURE_PLANE_ANGLE, plane, EGL_NONE};
1640 *image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1641 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1642 ASSERT_EGL_SUCCESS();
1643 ASSERT_NE(*image, EGL_NO_IMAGE_KHR);
1644
1645 // Create and bind Y plane texture to image.
1646 glGenTextures(1, texture);
1647 glActiveTexture(GL_TEXTURE0);
1648 glBindTexture(target, *texture);
1649 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1650 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1651 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1652 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1653 ASSERT_GL_NO_ERROR();
1654
1655 glEGLImageTargetTexture2DOES(target, *image);
1656 ASSERT_GL_NO_ERROR();
1657 }
1658
RunYUVSamplerTest(DXGI_FORMAT format)1659 void RunYUVSamplerTest(DXGI_FORMAT format)
1660 {
1661 ASSERT_TRUE(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
1662 format == DXGI_FORMAT_P016);
1663 UINT formatSupport;
1664 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
1665 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
1666 ASSERT_TRUE(formatSupport &
1667 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE));
1668
1669 const bool isNV12 = (format == DXGI_FORMAT_NV12);
1670 const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
1671 const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
1672 const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
1673
1674 constexpr char kVS[] =
1675 R"(precision highp float;
1676 attribute vec4 position;
1677 varying vec2 texcoord;
1678
1679 void main()
1680 {
1681 gl_Position = position;
1682 texcoord = (position.xy * 0.5) + 0.5;
1683 texcoord.y = 1.0 - texcoord.y;
1684 })";
1685
1686 constexpr char kFS[] =
1687 R"(#extension GL_OES_EGL_image_external : require
1688 precision highp float;
1689 uniform samplerExternalOES tex;
1690 varying vec2 texcoord;
1691
1692 void main()
1693 {
1694 gl_FragColor = texture2D(tex, texcoord);
1695 })";
1696
1697 GLuint program = CompileProgram(kVS, kFS);
1698 ASSERT_NE(0u, program) << "shader compilation failed.";
1699
1700 GLint textureLocation = glGetUniformLocation(program, "tex");
1701 ASSERT_NE(-1, textureLocation);
1702
1703 EGLWindow *window = getEGLWindow();
1704 EGLDisplay display = window->getDisplay();
1705
1706 window->makeCurrent();
1707
1708 const UINT bufferSize = 32;
1709 EXPECT_TRUE(mD3D11Device != nullptr);
1710 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
1711 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
1712 D3D11_BIND_SHADER_RESOURCE);
1713
1714 std::vector<unsigned char> imageData;
1715
1716 if (isNV12)
1717 {
1718 imageData.resize(bufferSize * bufferSize * 3 / 2);
1719 memset(imageData.data(), kYFillValue, bufferSize * bufferSize);
1720 const size_t kUVOffset = bufferSize * bufferSize;
1721 for (size_t i = 0; i < bufferSize * bufferSize / 2; i += 2)
1722 {
1723 imageData[kUVOffset + i] = kUFillValue;
1724 imageData[kUVOffset + i + 1] = kVFillValue;
1725 }
1726 }
1727 else
1728 {
1729 imageData.resize(bufferSize * bufferSize * 3);
1730 const size_t kUVOffset = bufferSize * bufferSize * 2;
1731 for (size_t i = 0; i < kUVOffset; i += 2)
1732 {
1733 imageData[i] = kYFillValue & 0xff;
1734 imageData[i + 1] = (kYFillValue >> 8) & 0xff;
1735 if (kUVOffset + i < imageData.size())
1736 {
1737 // Interleave U & V samples.
1738 const unsigned fill = (i % 4 == 0) ? kUFillValue : kVFillValue;
1739 imageData[kUVOffset + i] = fill & 0xff;
1740 imageData[kUVOffset + i + 1] = (fill >> 8) & 0xff;
1741 }
1742 }
1743 }
1744
1745 D3D11_SUBRESOURCE_DATA data = {};
1746 data.pSysMem = static_cast<const void *>(imageData.data());
1747 data.SysMemPitch = isNV12 ? bufferSize : bufferSize * 2;
1748
1749 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, &data, &d3d11Texture)));
1750
1751 // Create and bind Y plane texture to image.
1752 EGLImage yImage;
1753 GLuint yTexture;
1754
1755 GLenum internalFormat = format == DXGI_FORMAT_NV12 ? GL_RED_EXT : GL_R16_EXT;
1756 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat,
1757 GL_TEXTURE_EXTERNAL_OES, &yImage, &yTexture);
1758
1759 GLuint rbo;
1760 glGenRenderbuffers(1, &rbo);
1761 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
1762 glRenderbufferStorage(GL_RENDERBUFFER, isNV12 ? GL_RGBA8_OES : GL_RGBA16_EXT, bufferSize,
1763 bufferSize);
1764 ASSERT_GL_NO_ERROR();
1765
1766 GLuint fbo;
1767 glGenFramebuffers(1, &fbo);
1768 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1769 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
1770 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1771 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1772 ASSERT_GL_NO_ERROR();
1773
1774 // Draw the Y plane using a shader.
1775 glUseProgram(program);
1776 glUniform1i(textureLocation, 0);
1777 ASSERT_GL_NO_ERROR();
1778
1779 glViewport(0, 0, bufferSize, bufferSize);
1780 drawQuad(program, "position", 1.0f);
1781 ASSERT_GL_NO_ERROR();
1782
1783 if (isNV12)
1784 {
1785
1786 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1787 kYFillValue, 0, 0, 0xff);
1788 }
1789 else
1790 {
1791 EXPECT_PIXEL_16_NEAR(static_cast<GLint>(bufferSize) / 2,
1792 static_cast<GLint>(bufferSize) / 2, kYFillValue, 0, 0, 0xffff, 0);
1793 }
1794 ASSERT_GL_NO_ERROR();
1795
1796 // Create and bind UV plane texture to image.
1797 EGLImage uvImage;
1798 GLuint uvTexture;
1799
1800 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
1801 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat,
1802 GL_TEXTURE_EXTERNAL_OES, &uvImage, &uvTexture);
1803
1804 // Draw the UV plane using a shader.
1805 glUseProgram(program);
1806 glUniform1i(textureLocation, 0);
1807 ASSERT_GL_NO_ERROR();
1808
1809 // Use only half of the framebuffer to match UV plane dimensions.
1810 glViewport(0, 0, bufferSize / 2, bufferSize / 2);
1811 drawQuad(program, "position", 1.0f);
1812 ASSERT_GL_NO_ERROR();
1813
1814 if (isNV12)
1815 {
1816
1817 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 4, static_cast<GLint>(bufferSize) / 4,
1818 kUFillValue, kVFillValue, 0, 0xff);
1819 }
1820 else
1821 {
1822 EXPECT_PIXEL_16_NEAR(static_cast<GLint>(bufferSize) / 4,
1823 static_cast<GLint>(bufferSize) / 4, kUFillValue, kVFillValue, 0,
1824 0xffff, 0);
1825 }
1826 ASSERT_GL_NO_ERROR();
1827
1828 glDeleteProgram(program);
1829 glDeleteTextures(1, &yTexture);
1830 glDeleteTextures(1, &uvTexture);
1831 glDeleteFramebuffers(1, &fbo);
1832 glDeleteRenderbuffers(1, &rbo);
1833 eglDestroyImageKHR(display, yImage);
1834 eglDestroyImageKHR(display, uvImage);
1835 }
1836
RunYUVRenderTest(DXGI_FORMAT format)1837 void RunYUVRenderTest(DXGI_FORMAT format)
1838 {
1839 ASSERT(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
1840 format == DXGI_FORMAT_P016);
1841 UINT formatSupport;
1842 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
1843 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
1844 ASSERT_TRUE(formatSupport &
1845 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET));
1846
1847 const bool isNV12 = (format == DXGI_FORMAT_NV12);
1848 const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
1849 const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
1850 const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
1851
1852 constexpr char kVS[] =
1853 R"(precision highp float;
1854 attribute vec4 position;
1855 varying vec2 texcoord;
1856
1857 void main()
1858 {
1859 gl_Position = position;
1860 texcoord = (position.xy * 0.5) + 0.5;
1861 texcoord.y = 1.0 - texcoord.y;
1862 })";
1863
1864 constexpr char kFS[] =
1865 R"(precision highp float;
1866 uniform vec4 color;
1867 varying vec2 texcoord;
1868
1869 void main()
1870 {
1871 gl_FragColor = color;
1872 })";
1873
1874 GLuint program = CompileProgram(kVS, kFS);
1875 ASSERT_NE(0u, program) << "shader compilation failed.";
1876
1877 GLint colorLocation = glGetUniformLocation(program, "color");
1878 ASSERT_NE(-1, colorLocation);
1879
1880 EGLWindow *window = getEGLWindow();
1881 EGLDisplay display = window->getDisplay();
1882
1883 window->makeCurrent();
1884
1885 const UINT bufferSize = 32;
1886 EXPECT_TRUE(mD3D11Device != nullptr);
1887 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
1888 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
1889 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1890
1891 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1892
1893 // Create and bind Y plane texture to image.
1894 EGLImage yImage;
1895 GLuint yTexture;
1896
1897 GLenum internalFormat = format == DXGI_FORMAT_NV12 ? GL_RED_EXT : GL_R16_EXT;
1898 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat, GL_TEXTURE_2D,
1899 &yImage, &yTexture);
1900
1901 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, yImage);
1902 ASSERT_GL_NO_ERROR();
1903
1904 GLuint fbo;
1905 glGenFramebuffers(1, &fbo);
1906 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1907 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yTexture, 0);
1908 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1909 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1910 ASSERT_GL_NO_ERROR();
1911
1912 // Draw the Y plane using a shader.
1913 glUseProgram(program);
1914 glUniform4f(colorLocation, kYFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0, 0);
1915 ASSERT_GL_NO_ERROR();
1916
1917 drawQuad(program, "position", 1.0f);
1918 ASSERT_GL_NO_ERROR();
1919
1920 // Create and bind UV plane texture to image.
1921 EGLImage uvImage;
1922 GLuint uvTexture;
1923
1924 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
1925 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat, GL_TEXTURE_2D,
1926 &uvImage, &uvTexture);
1927
1928 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uvTexture, 0);
1929 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1930 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1931 ASSERT_GL_NO_ERROR();
1932
1933 // Draw the UV plane using a shader.
1934 glUseProgram(program);
1935 glUniform4f(colorLocation, kUFillValue * 1.0f / (isNV12 ? 0xff : 0xffff),
1936 kVFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0);
1937 ASSERT_GL_NO_ERROR();
1938
1939 drawQuad(program, "position", 1.0f);
1940 ASSERT_GL_NO_ERROR();
1941
1942 Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture;
1943 CD3D11_TEXTURE2D_DESC stagingDesc = desc;
1944 stagingDesc.BindFlags = 0;
1945 stagingDesc.Usage = D3D11_USAGE_STAGING;
1946 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1947
1948 EXPECT_TRUE(
1949 SUCCEEDED(mD3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture)));
1950
1951 Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
1952 mD3D11Device->GetImmediateContext(&context);
1953
1954 context->CopyResource(stagingTexture.Get(), d3d11Texture.Get());
1955 ASSERT_GL_NO_ERROR();
1956
1957 D3D11_MAPPED_SUBRESOURCE mapped = {};
1958 EXPECT_TRUE(SUCCEEDED(context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mapped)));
1959
1960 uint8_t *yPlane = reinterpret_cast<uint8_t *>(mapped.pData);
1961 uint8_t *uvPlane = yPlane + bufferSize * mapped.RowPitch;
1962 if (isNV12)
1963 {
1964 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue);
1965 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue);
1966 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], kVFillValue);
1967 }
1968 else
1969 {
1970 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue & 0xff);
1971 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2 + 1], (kYFillValue >> 8) & 0xff);
1972 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue & 0xff);
1973 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], (kUFillValue >> 8) & 0xff);
1974 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 2], kVFillValue & 0xff);
1975 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 3], (kVFillValue >> 8) & 0xff);
1976 }
1977
1978 context->Unmap(stagingTexture.Get(), 0);
1979
1980 glDeleteProgram(program);
1981 glDeleteTextures(1, &yTexture);
1982 glDeleteTextures(1, &uvTexture);
1983 glDeleteFramebuffers(1, &fbo);
1984 eglDestroyImageKHR(display, yImage);
1985 eglDestroyImageKHR(display, uvImage);
1986 }
1987
RunYUVReadPixelTest(DXGI_FORMAT format)1988 void RunYUVReadPixelTest(DXGI_FORMAT format)
1989 {
1990 ASSERT(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
1991 format == DXGI_FORMAT_P016);
1992 UINT formatSupport;
1993 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
1994 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
1995 ASSERT_TRUE(formatSupport &
1996 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET));
1997
1998 const bool isNV12 = (format == DXGI_FORMAT_NV12);
1999 const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
2000 const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
2001 const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
2002
2003 constexpr char kVS[] =
2004 R"(precision highp float;
2005 attribute vec4 position;
2006 varying vec2 texcoord;
2007
2008 void main()
2009 {
2010 gl_Position = position;
2011 texcoord = (position.xy * 0.5) + 0.5;
2012 texcoord.y = 1.0 - texcoord.y;
2013 })";
2014
2015 constexpr char kFS[] =
2016 R"(precision highp float;
2017 uniform vec4 color;
2018 varying vec2 texcoord;
2019
2020 void main()
2021 {
2022 gl_FragColor = color;
2023 })";
2024
2025 GLuint program = CompileProgram(kVS, kFS);
2026 ASSERT_NE(0u, program) << "shader compilation failed.";
2027
2028 GLint colorLocation = glGetUniformLocation(program, "color");
2029 ASSERT_NE(-1, colorLocation);
2030
2031 EGLWindow *window = getEGLWindow();
2032 EGLDisplay display = window->getDisplay();
2033
2034 window->makeCurrent();
2035
2036 const UINT bufferSize = 32;
2037 EXPECT_TRUE(mD3D11Device != nullptr);
2038 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
2039 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
2040 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
2041
2042 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
2043
2044 // Create and bind Y plane texture to image.
2045 EGLImage yImage;
2046 GLuint yTexture;
2047
2048 GLenum internalFormat = format == DXGI_FORMAT_NV12 ? GL_RED_EXT : GL_R16_EXT;
2049 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat, GL_TEXTURE_2D,
2050 &yImage, &yTexture);
2051
2052 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, yImage);
2053 ASSERT_GL_NO_ERROR();
2054
2055 GLuint fbo;
2056 glGenFramebuffers(1, &fbo);
2057 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2058 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yTexture, 0);
2059 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2060 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2061 ASSERT_GL_NO_ERROR();
2062
2063 // Draw the Y plane using a shader.
2064 glUseProgram(program);
2065 glUniform4f(colorLocation, kYFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0, 0);
2066 ASSERT_GL_NO_ERROR();
2067
2068 drawQuad(program, "position", 1.0f);
2069 ASSERT_GL_NO_ERROR();
2070
2071 // Read the Y plane pixels.
2072 if (isNV12)
2073 {
2074 GLubyte yPixels[4] = {};
2075 glReadPixels(0, bufferSize / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, yPixels);
2076 EXPECT_EQ(yPixels[0], kYFillValue);
2077 }
2078 else
2079 {
2080 GLushort yPixels[4] = {};
2081 glReadPixels(0, bufferSize / 2, 1, 1, GL_RGBA, GL_UNSIGNED_SHORT, yPixels);
2082 EXPECT_EQ(yPixels[0], kYFillValue);
2083 }
2084
2085 // Create and bind UV plane texture to image.
2086 EGLImage uvImage;
2087 GLuint uvTexture;
2088
2089 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
2090 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat, GL_TEXTURE_2D,
2091 &uvImage, &uvTexture);
2092
2093 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uvTexture, 0);
2094 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2095 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2096 ASSERT_GL_NO_ERROR();
2097
2098 // Draw the UV plane using a shader.
2099 glUseProgram(program);
2100 glUniform4f(colorLocation, kUFillValue * 1.0f / (isNV12 ? 0xff : 0xffff),
2101 kVFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0);
2102 ASSERT_GL_NO_ERROR();
2103
2104 drawQuad(program, "position", 1.0f);
2105 ASSERT_GL_NO_ERROR();
2106
2107 // Read the UV plane pixels.
2108 if (isNV12)
2109 {
2110 GLubyte uvPixels[4] = {};
2111 glReadPixels(0, bufferSize / 4, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, uvPixels);
2112 EXPECT_EQ(uvPixels[0], kUFillValue);
2113 EXPECT_EQ(uvPixels[1], kVFillValue);
2114 }
2115 else
2116 {
2117 GLushort uvPixels[4] = {};
2118 glReadPixels(0, bufferSize / 4, 1, 1, GL_RGBA, GL_UNSIGNED_SHORT, uvPixels);
2119 EXPECT_EQ(uvPixels[0], kUFillValue);
2120 EXPECT_EQ(uvPixels[1], kVFillValue);
2121 }
2122
2123 Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture;
2124 CD3D11_TEXTURE2D_DESC stagingDesc = desc;
2125 stagingDesc.BindFlags = 0;
2126 stagingDesc.Usage = D3D11_USAGE_STAGING;
2127 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
2128
2129 EXPECT_TRUE(
2130 SUCCEEDED(mD3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture)));
2131
2132 Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
2133 mD3D11Device->GetImmediateContext(&context);
2134
2135 context->CopyResource(stagingTexture.Get(), d3d11Texture.Get());
2136 ASSERT_GL_NO_ERROR();
2137
2138 D3D11_MAPPED_SUBRESOURCE mapped = {};
2139 EXPECT_TRUE(SUCCEEDED(context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mapped)));
2140
2141 uint8_t *yPlane = reinterpret_cast<uint8_t *>(mapped.pData);
2142 uint8_t *uvPlane = yPlane + bufferSize * mapped.RowPitch;
2143 if (isNV12)
2144 {
2145 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue);
2146 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue);
2147 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], kVFillValue);
2148 }
2149 else
2150 {
2151 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue & 0xff);
2152 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2 + 1], (kYFillValue >> 8) & 0xff);
2153 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue & 0xff);
2154 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], (kUFillValue >> 8) & 0xff);
2155 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 2], kVFillValue & 0xff);
2156 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 3], (kVFillValue >> 8) & 0xff);
2157 }
2158
2159 context->Unmap(stagingTexture.Get(), 0);
2160
2161 glDeleteProgram(program);
2162 glDeleteTextures(1, &yTexture);
2163 glDeleteTextures(1, &uvTexture);
2164 glDeleteFramebuffers(1, &fbo);
2165 eglDestroyImageKHR(display, yImage);
2166 eglDestroyImageKHR(display, uvImage);
2167 }
2168
2169 template <typename T>
RunYUVWritePixelTest(DXGI_FORMAT format)2170 void RunYUVWritePixelTest(DXGI_FORMAT format)
2171 {
2172 ASSERT(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
2173 format == DXGI_FORMAT_P016);
2174 UINT formatSupport;
2175 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
2176 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
2177 ASSERT_TRUE(formatSupport &
2178 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET));
2179
2180 const bool isNV12 = (format == DXGI_FORMAT_NV12);
2181 const unsigned kYFillValueFull = isNV12 ? 0x12 : 0x1234;
2182 const unsigned kUFillValueFull = isNV12 ? 0x23 : 0x2345;
2183 const unsigned kVFillValueFull = isNV12 ? 0x34 : 0x3456;
2184 const unsigned kYFillValueOffset = isNV12 ? 0x56 : 0x5678;
2185 const unsigned kUFillValueOffset = isNV12 ? 0x67 : 0x6789;
2186 const unsigned kVFillValueOffset = isNV12 ? 0x78 : 0x7890;
2187
2188 EGLWindow *window = getEGLWindow();
2189 EGLDisplay display = window->getDisplay();
2190 window->makeCurrent();
2191
2192 const UINT bufferSize = 32;
2193 EXPECT_TRUE(mD3D11Device != nullptr);
2194 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
2195 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
2196 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
2197
2198 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
2199
2200 // Create and bind Y plane texture to image.
2201 EGLImage yImage;
2202 GLuint yTexture;
2203 GLenum internalFormat = isNV12 ? GL_RED_EXT : GL_R16_EXT;
2204 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat, GL_TEXTURE_2D,
2205 &yImage, &yTexture);
2206 ASSERT_GL_NO_ERROR();
2207
2208 // Write the Y plane data to full texture (0, 0) to (32, 32).
2209 GLenum type = isNV12 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
2210 std::vector<T> yData(bufferSize * bufferSize, kYFillValueFull);
2211 glTexSubImage2D(GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0, /*yoffset=*/0,
2212 /*width=*/bufferSize,
2213 /*height=*/bufferSize, GL_RED_EXT, type, yData.data());
2214 ASSERT_GL_NO_ERROR();
2215
2216 GLuint fbo;
2217 glGenFramebuffers(1, &fbo);
2218 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2219 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yTexture, 0);
2220 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2221 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2222 ASSERT_GL_NO_ERROR();
2223
2224 // Read the Y plane pixels for a region starting at 0, 0 offsets.
2225 // yPixels of size (4*4) region (*4) bytes per RGBA pixel
2226 T yPixels[4 * 4 * 4] = {};
2227 glReadPixels(/*x=*/0, /*y=*/0, /*width*/ 4, /*height=*/4, GL_RGBA, type, yPixels);
2228 EXPECT_EQ(yPixels[0], kYFillValueFull);
2229 EXPECT_EQ(yPixels[4], kYFillValueFull);
2230 EXPECT_EQ(yPixels[16], kYFillValueFull);
2231
2232 // Write the Y plane data with offseted values for subregion (16, 16) - (32, 32).
2233 std::vector<T> yDataOffset(bufferSize * bufferSize, kYFillValueOffset);
2234 glTexSubImage2D(GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/bufferSize / 2,
2235 /*yoffset=*/bufferSize / 2, /*width=*/bufferSize / 2,
2236 /*height=*/bufferSize / 2, GL_RED_EXT, type, yDataOffset.data());
2237 ASSERT_GL_NO_ERROR();
2238
2239 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yTexture, 0);
2240 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2241 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2242 ASSERT_GL_NO_ERROR();
2243
2244 // Read the Y plane pixels for a region starting at some offsets.
2245 // yPixels of size (16*16) region (*4) bytes per RGBA pixel
2246 T yPixelsOffset[16 * 16 * 4] = {};
2247 glReadPixels(/*x=*/bufferSize / 2, /*y=*/bufferSize / 2, /*width=*/bufferSize / 2,
2248 /*height=*/bufferSize / 2, GL_RGBA, type, yPixelsOffset);
2249 EXPECT_EQ(yPixelsOffset[0], kYFillValueOffset);
2250 EXPECT_EQ(yPixelsOffset[12], kYFillValueOffset);
2251
2252 // Create and bind UV plane texture to image.
2253 EGLImage uvImage;
2254 GLuint uvTexture;
2255 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
2256 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat, GL_TEXTURE_2D,
2257 &uvImage, &uvTexture);
2258 ASSERT_GL_NO_ERROR();
2259
2260 // Write the UV plane data to texture's full uv plane (0, 0,) - (16, 16).
2261 std::vector<T> uvData((bufferSize * bufferSize) / 2);
2262 for (UINT i = 0; i < (bufferSize * bufferSize) / 2; i++)
2263 {
2264 uvData[i] = i % 2 == 0 ? kUFillValueFull : kVFillValueFull;
2265 }
2266 glTexSubImage2D(GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0, /*yoffset=*/0,
2267 /*width=*/bufferSize / 2,
2268 /*height=*/bufferSize / 2, GL_RG_EXT, type, uvData.data());
2269 ASSERT_GL_NO_ERROR();
2270
2271 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uvTexture, 0);
2272 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2273 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2274 ASSERT_GL_NO_ERROR();
2275
2276 // Read the UV plane pixels for a region starting at 0, 0 offsets.
2277 // uvPixels of size (4*4) region (*4) bytes per RGBA pixel
2278 T uvPixels[4 * 4 * 4] = {};
2279 glReadPixels(/*x=*/0, /*y=*/0, /*width=*/4, /*height=*/4, GL_RGBA, type, uvPixels);
2280 EXPECT_EQ(uvPixels[0], kUFillValueFull);
2281 EXPECT_EQ(uvPixels[1], kVFillValueFull);
2282 EXPECT_EQ(uvPixels[4], kUFillValueFull);
2283 EXPECT_EQ(uvPixels[5], kVFillValueFull);
2284 EXPECT_EQ(uvPixels[16], kUFillValueFull);
2285 EXPECT_EQ(uvPixels[17], kVFillValueFull);
2286
2287 // Write the UV plane data with offset values for subregion (8, 8) - (16, 16).
2288 std::vector<T> uvDataOffset((bufferSize * bufferSize) / 2);
2289 for (UINT i = 0; i < (bufferSize * bufferSize) / 2; i++)
2290 {
2291 uvDataOffset[i] = i % 2 == 0 ? kUFillValueOffset : kVFillValueOffset;
2292 }
2293 glTexSubImage2D(GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/bufferSize / 4,
2294 /*yoffset=*/bufferSize / 4, /*width=*/bufferSize / 4,
2295 /*height=*/bufferSize / 4, GL_RG_EXT, type, uvDataOffset.data());
2296 ASSERT_GL_NO_ERROR();
2297
2298 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uvTexture, 0);
2299 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2300 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2301 ASSERT_GL_NO_ERROR();
2302
2303 // Read the UV plane pixels for a region starting at some offsets.
2304 // uvPixels of size (8*8) region (*4) bytes per RGBA pixel
2305 T uvPixelsOffset[8 * 8 * 4] = {};
2306 glReadPixels(/*x=*/bufferSize / 4, /*y=*/bufferSize / 4, /*width=*/bufferSize / 4,
2307 /*height=*/bufferSize / 4, GL_RGBA, type, uvPixelsOffset);
2308 EXPECT_EQ(uvPixelsOffset[0], kUFillValueOffset);
2309 EXPECT_EQ(uvPixelsOffset[1], kVFillValueOffset);
2310 EXPECT_EQ(uvPixelsOffset[12], kUFillValueOffset);
2311 EXPECT_EQ(uvPixelsOffset[13], kVFillValueOffset);
2312
2313 Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture;
2314 CD3D11_TEXTURE2D_DESC stagingDesc = desc;
2315 stagingDesc.BindFlags = 0;
2316 stagingDesc.Usage = D3D11_USAGE_STAGING;
2317 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
2318
2319 EXPECT_TRUE(
2320 SUCCEEDED(mD3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture)));
2321
2322 Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
2323 mD3D11Device->GetImmediateContext(&context);
2324
2325 context->CopyResource(stagingTexture.Get(), d3d11Texture.Get());
2326 ASSERT_GL_NO_ERROR();
2327
2328 D3D11_MAPPED_SUBRESOURCE mapped = {};
2329 EXPECT_TRUE(SUCCEEDED(context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mapped)));
2330
2331 uint8_t *yPlane = reinterpret_cast<uint8_t *>(mapped.pData);
2332 uint8_t *uvPlane = yPlane + bufferSize * mapped.RowPitch;
2333 auto getYValue = [&](int x, int y) {
2334 const T *lineStart = reinterpret_cast<const T *>(yPlane + y * mapped.RowPitch);
2335 return lineStart[x];
2336 };
2337
2338 auto getUValue = [&](int x, int y) {
2339 const T *lineStart = reinterpret_cast<const T *>(uvPlane + y * mapped.RowPitch);
2340 return lineStart[x * 2 + 0];
2341 };
2342
2343 auto getVValue = [&](int x, int y) {
2344 const T *lineStart = reinterpret_cast<const T *>(uvPlane + y * mapped.RowPitch);
2345 return lineStart[x * 2 + 1];
2346 };
2347 // Compare first y pixel with full write values.
2348 EXPECT_EQ(getYValue(0, 0), kYFillValueFull);
2349 // Compare last y pixel with overwritten subregion values.
2350 EXPECT_EQ(getYValue(bufferSize - 1, bufferSize - 1), kYFillValueOffset);
2351 // Compare first uv pixel with full write values.
2352 EXPECT_EQ(getUValue(0, 0), kUFillValueFull);
2353 EXPECT_EQ(getVValue(0, 0), kVFillValueFull);
2354 // Compare last uv pixel with overwritten subregion values.
2355 EXPECT_EQ(getUValue(bufferSize / 2 - 1, bufferSize / 2 - 1), kUFillValueOffset);
2356 EXPECT_EQ(getVValue(bufferSize / 2 - 1, bufferSize / 2 - 1), kVFillValueOffset);
2357
2358 context->Unmap(stagingTexture.Get(), 0);
2359
2360 glDeleteTextures(1, &yTexture);
2361 glDeleteTextures(1, &uvTexture);
2362 glDeleteFramebuffers(1, &fbo);
2363 eglDestroyImageKHR(display, yImage);
2364 eglDestroyImageKHR(display, uvImage);
2365 }
2366 };
2367
2368 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and the resulting GL
2369 // textures can be sampled from.
TEST_P(D3DTextureYUVTest,NV12TextureImageSampler)2370 TEST_P(D3DTextureYUVTest, NV12TextureImageSampler)
2371 {
2372 RunYUVSamplerTest(DXGI_FORMAT_NV12);
2373 }
2374
2375 // ANGLE ES2/D3D11 supports GL_EXT_texture_norm16 even though the extension spec says it's ES3 only.
2376 // Test P010 on ES2 since Chromium's Skia context is ES2 and it uses P010 for HDR video playback.
TEST_P(D3DTextureYUVTest,P010TextureImageSampler)2377 TEST_P(D3DTextureYUVTest, P010TextureImageSampler)
2378 {
2379 RunYUVSamplerTest(DXGI_FORMAT_P010);
2380 }
2381
2382 // Same as above, but for P016. P016 doesn't seem to be supported on all GPUs so it might be skipped
2383 // more often than P010 and NV12 e.g. on the NVIDIA GTX 1050 Ti.
TEST_P(D3DTextureYUVTest,P016TextureImageSampler)2384 TEST_P(D3DTextureYUVTest, P016TextureImageSampler)
2385 {
2386 RunYUVSamplerTest(DXGI_FORMAT_P016);
2387 }
2388
2389 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and rendered to as
2390 // framebuffer attachments.
TEST_P(D3DTextureYUVTest,NV12TextureImageRender)2391 TEST_P(D3DTextureYUVTest, NV12TextureImageRender)
2392 {
2393 RunYUVRenderTest(DXGI_FORMAT_NV12);
2394 }
2395
2396 // ANGLE ES2/D3D11 supports GL_EXT_texture_norm16 even though the extension spec says it's ES3 only.
2397 // Test P010 on ES2 since Chromium's Skia context is ES2 and it uses P010 for HDR video playback.
TEST_P(D3DTextureYUVTest,P010TextureImageRender)2398 TEST_P(D3DTextureYUVTest, P010TextureImageRender)
2399 {
2400 RunYUVRenderTest(DXGI_FORMAT_P010);
2401 }
2402
2403 // Same as above, but for P016. P016 doesn't seem to be supported on all GPUs so it might be skipped
2404 // more often than P010 and NV12 e.g. on the NVIDIA GTX 1050 Ti.
TEST_P(D3DTextureYUVTest,P016TextureImageRender)2405 TEST_P(D3DTextureYUVTest, P016TextureImageRender)
2406 {
2407 RunYUVRenderTest(DXGI_FORMAT_P016);
2408 }
2409
2410 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and rendered to as
2411 // framebuffer attachments and then read from as individual planes.
TEST_P(D3DTextureYUVTest,NV12TextureImageReadPixel)2412 TEST_P(D3DTextureYUVTest, NV12TextureImageReadPixel)
2413 {
2414 RunYUVReadPixelTest(DXGI_FORMAT_NV12);
2415 }
2416
2417 // ANGLE ES2/D3D11 supports GL_EXT_texture_norm16 even though the extension spec says it's ES3 only.
2418 // Test P010 on ES2 since Chromium's Skia context is ES2 and it uses P010 for HDR video playback.
TEST_P(D3DTextureYUVTest,P010TextureImageReadPixel)2419 TEST_P(D3DTextureYUVTest, P010TextureImageReadPixel)
2420 {
2421 RunYUVReadPixelTest(DXGI_FORMAT_P010);
2422 }
2423
2424 // Same as above, but for P016. P016 doesn't seem to be supported on all GPUs so it might be skipped
2425 // more often than P010 and NV12 e.g. on the NVIDIA GTX 1050 Ti.
TEST_P(D3DTextureYUVTest,P016TextureImageReadPixel)2426 TEST_P(D3DTextureYUVTest, P016TextureImageReadPixel)
2427 {
2428 RunYUVReadPixelTest(DXGI_FORMAT_P016);
2429 }
2430
2431 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and write data to
2432 // them through glTexSubImage2D and then rendered to as framebuffer attachments and then read from
2433 // as individual planes.
TEST_P(D3DTextureYUVTest,NV12TextureImageWritePixel)2434 TEST_P(D3DTextureYUVTest, NV12TextureImageWritePixel)
2435 {
2436 RunYUVWritePixelTest<uint8_t>(DXGI_FORMAT_NV12);
2437 }
2438
2439 // Test that an P010 D3D11 texture can be imported as two R16 and RG16 EGLImages and write data to
2440 // them through glTexSubImage2D and then rendered to as framebuffer attachments and then read from
2441 // as individual planes.
TEST_P(D3DTextureYUVTest,P010TextureImageWritePixel)2442 TEST_P(D3DTextureYUVTest, P010TextureImageWritePixel)
2443 {
2444 RunYUVWritePixelTest<uint16_t>(DXGI_FORMAT_P010);
2445 }
2446
2447 // Test that an P016 D3D11 texture can be imported as two R16 and RG16 EGLImages and write data to
2448 // them through glTexSubImage2D and then rendered to as framebuffer attachments and then read from
2449 // as individual planes.
TEST_P(D3DTextureYUVTest,P016TextureImageWritePixel)2450 TEST_P(D3DTextureYUVTest, P016TextureImageWritePixel)
2451 {
2452 RunYUVWritePixelTest<uint16_t>(DXGI_FORMAT_P016);
2453 }
2454
2455 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
2456 // tests should be run against.
2457 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureTest);
2458 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureClearTest);
2459 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureYUVTest);
2460 ANGLE_INSTANTIATE_TEST_ES3(D3DTextureTestES3);
2461 // D3D Debug device reports an error. http://anglebug.com/40096593
2462 // ANGLE_INSTANTIATE_TEST(D3DTextureTestMS, ES2_D3D11());
2463 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(D3DTextureTestMS);
2464 } // namespace angle
2465