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
1287 {
1288 GLuint readColor[4] = {0, 0, 0, 255};
1289 switch (internalFormat)
1290 {
1291 case GL_RGBA:
1292 case GL_BGRA_EXT:
1293 case GL_RGB10_A2_EXT:
1294 readColor[0] = readColor[1] = readColor[2] = 255;
1295 break;
1296 case GL_RG_EXT:
1297 case GL_RG16_EXT:
1298 readColor[0] = readColor[1] = 255;
1299 break;
1300 case GL_RED_EXT:
1301 case GL_R16_EXT:
1302 readColor[0] = 255;
1303 break;
1304 }
1305 // Read back as GL_UNSIGNED_BYTE even though the texture might have more than 8bpc.
1306 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1307 readColor[0], readColor[1], readColor[2], readColor[3]);
1308 }
1309
1310 glDeleteFramebuffers(1, &fbo);
1311 glDeleteTextures(1, &texture);
1312 eglDestroyImageKHR(display, image);
1313
1314 d3d11Texture->Release();
1315 }
1316 };
1317
TEST_P(D3DTextureClearTest,ClearRGBA8)1318 TEST_P(D3DTextureClearTest, ClearRGBA8)
1319 {
1320 RunClearTest(DXGI_FORMAT_R8G8B8A8_UNORM);
1321 }
1322
TEST_P(D3DTextureClearTest,ClearBGRA8)1323 TEST_P(D3DTextureClearTest, ClearBGRA8)
1324 {
1325 RunClearTest(DXGI_FORMAT_B8G8R8A8_UNORM);
1326 }
1327
TEST_P(D3DTextureClearTest,ClearR8)1328 TEST_P(D3DTextureClearTest, ClearR8)
1329 {
1330 RunClearTest(DXGI_FORMAT_R8_UNORM);
1331 }
1332
TEST_P(D3DTextureClearTest,ClearRG8)1333 TEST_P(D3DTextureClearTest, ClearRG8)
1334 {
1335 RunClearTest(DXGI_FORMAT_R8G8_UNORM);
1336 }
1337
TEST_P(D3DTextureClearTest,ClearRGB10A2)1338 TEST_P(D3DTextureClearTest, ClearRGB10A2)
1339 {
1340 RunClearTest(DXGI_FORMAT_R10G10B10A2_UNORM);
1341 }
1342
TEST_P(D3DTextureClearTest,ClearRGBAF16)1343 TEST_P(D3DTextureClearTest, ClearRGBAF16)
1344 {
1345 RunClearTest(DXGI_FORMAT_R16G16B16A16_FLOAT);
1346 }
1347
TEST_P(D3DTextureClearTest,ClearR16)1348 TEST_P(D3DTextureClearTest, ClearR16)
1349 {
1350 RunClearTest(DXGI_FORMAT_R16_UNORM);
1351 }
1352
TEST_P(D3DTextureClearTest,ClearRG16)1353 TEST_P(D3DTextureClearTest, ClearRG16)
1354 {
1355 RunClearTest(DXGI_FORMAT_R16G16_UNORM);
1356 }
1357
TEST_P(D3DTextureTest,NonRenderableTextureImage)1358 TEST_P(D3DTextureTest, NonRenderableTextureImage)
1359 {
1360 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1361
1362 EGLWindow *window = getEGLWindow();
1363 EGLDisplay display = window->getDisplay();
1364
1365 window->makeCurrent();
1366
1367 const UINT bufferSize = 32;
1368 EXPECT_TRUE(mD3D11Device != nullptr);
1369 ID3D11Texture2D *d3d11Texture = nullptr;
1370 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1,
1371 D3D11_BIND_SHADER_RESOURCE);
1372 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1373
1374 const EGLint attribs[] = {EGL_NONE};
1375
1376 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1377 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1378 ASSERT_EGL_SUCCESS();
1379 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1380
1381 GLuint texture;
1382 glGenTextures(1, &texture);
1383 glBindTexture(GL_TEXTURE_2D, texture);
1384 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1385 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1386 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1387 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1388 ASSERT_GL_NO_ERROR();
1389
1390 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1391 ASSERT_GL_NO_ERROR();
1392
1393 GLuint fbo;
1394 glGenFramebuffers(1, &fbo);
1395 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1396 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1397 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1398 static_cast<unsigned>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT));
1399 ASSERT_GL_NO_ERROR();
1400
1401 glDeleteFramebuffers(1, &fbo);
1402 glDeleteTextures(1, &texture);
1403 eglDestroyImageKHR(display, image);
1404
1405 d3d11Texture->Release();
1406 }
1407
TEST_P(D3DTextureTest,RGBEmulationTextureImage)1408 TEST_P(D3DTextureTest, RGBEmulationTextureImage)
1409 {
1410 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1411
1412 EGLWindow *window = getEGLWindow();
1413 EGLDisplay display = window->getDisplay();
1414
1415 window->makeCurrent();
1416
1417 const UINT bufferSize = 32;
1418 EXPECT_TRUE(mD3D11Device != nullptr);
1419 ID3D11Texture2D *d3d11Texture = nullptr;
1420 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1,
1421 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1422 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1423
1424 const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGB, EGL_NONE};
1425
1426 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1427 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1428 ASSERT_EGL_SUCCESS();
1429 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1430
1431 GLuint texture;
1432 glGenTextures(1, &texture);
1433 glBindTexture(GL_TEXTURE_2D, texture);
1434 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1435 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1436 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1437 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1438 ASSERT_GL_NO_ERROR();
1439
1440 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1441 ASSERT_GL_NO_ERROR();
1442
1443 GLuint fbo;
1444 glGenFramebuffers(1, &fbo);
1445 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1446 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1447 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1448 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1449 ASSERT_GL_NO_ERROR();
1450
1451 // Although we are writing 0.5 to the alpha channel it should have the same
1452 // side effects as if alpha were 1.0.
1453 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1454 glClearColor(1.0f, 0.0f, 1.0f, 0.5f);
1455 glClear(GL_COLOR_BUFFER_BIT);
1456 ASSERT_GL_NO_ERROR();
1457 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
1458 255, 255);
1459
1460 GLuint rgbaRbo;
1461 glGenRenderbuffers(1, &rgbaRbo);
1462 glBindRenderbuffer(GL_RENDERBUFFER, rgbaRbo);
1463 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, bufferSize, bufferSize);
1464
1465 GLuint rgbaFbo;
1466 glGenFramebuffers(1, &rgbaFbo);
1467 glBindFramebuffer(GL_FRAMEBUFFER, rgbaFbo);
1468 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rgbaRbo);
1469 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1470 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1471 ASSERT_GL_NO_ERROR();
1472
1473 // BlitFramebuffer from/to RGBA framebuffer fails.
1474 glBindFramebuffer(GL_READ_FRAMEBUFFER, rgbaFbo);
1475 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1476 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1477 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1478 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1479 ASSERT_GL_NO_ERROR();
1480
1481 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
1482 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rgbaFbo);
1483 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1484 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1485 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1486 ASSERT_GL_NO_ERROR();
1487
1488 GLuint rgbRbo;
1489 glGenRenderbuffers(1, &rgbRbo);
1490 glBindRenderbuffer(GL_RENDERBUFFER, rgbRbo);
1491 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, bufferSize, bufferSize);
1492
1493 GLuint rgbFbo;
1494 glGenFramebuffers(1, &rgbFbo);
1495 glBindFramebuffer(GL_FRAMEBUFFER, rgbFbo);
1496 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rgbRbo);
1497 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1498 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1499 ASSERT_GL_NO_ERROR();
1500 glClearColor(1.0f, 0.0f, 1.0f, 0.5f);
1501 glClear(GL_COLOR_BUFFER_BIT);
1502 ASSERT_GL_NO_ERROR();
1503
1504 // Clear texture framebuffer.
1505 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1506 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1507 glClear(GL_COLOR_BUFFER_BIT);
1508 ASSERT_GL_NO_ERROR();
1509 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 0, 0, 0,
1510 255);
1511
1512 // BlitFramebuffer from/to RGB framebuffer succeeds.
1513 glBindFramebuffer(GL_READ_FRAMEBUFFER, rgbFbo);
1514 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1515 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1516 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1517 ASSERT_GL_NO_ERROR();
1518 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
1519 255, 255);
1520
1521 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1522 glClear(GL_COLOR_BUFFER_BIT);
1523 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
1524 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rgbFbo);
1525 glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize,
1526 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1527 ASSERT_GL_NO_ERROR();
1528 glBindFramebuffer(GL_FRAMEBUFFER, rgbFbo);
1529 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 0, 0, 0,
1530 255);
1531
1532 glDeleteFramebuffers(1, &rgbFbo);
1533 glDeleteRenderbuffers(1, &rgbRbo);
1534 glDeleteFramebuffers(1, &rgbaFbo);
1535 glDeleteRenderbuffers(1, &rgbaRbo);
1536 glDeleteFramebuffers(1, &fbo);
1537 glDeleteTextures(1, &texture);
1538 eglDestroyImageKHR(display, image);
1539
1540 d3d11Texture->Release();
1541 }
1542
TEST_P(D3DTextureTest,TextureArray)1543 TEST_P(D3DTextureTest, TextureArray)
1544 {
1545 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
1546
1547 EGLWindow *window = getEGLWindow();
1548 EGLDisplay display = window->getDisplay();
1549
1550 window->makeCurrent();
1551
1552 const UINT bufferSize = 32;
1553 const UINT arraySize = 4;
1554
1555 ID3D11Texture2D *d3d11Texture = nullptr;
1556 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, arraySize, 1,
1557 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1558 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1559
1560 const unsigned char kRFill = 0x12;
1561 const unsigned char kGFill = 0x23;
1562 const unsigned char kBFill = 0x34;
1563 const unsigned char kAFill = 0x45;
1564
1565 std::vector<unsigned char> imageData(bufferSize * bufferSize * 4, 0);
1566 for (size_t i = 0; i < imageData.size(); i += 4)
1567 {
1568 imageData[i] = kRFill;
1569 imageData[i + 1] = kGFill;
1570 imageData[i + 2] = kBFill;
1571 imageData[i + 3] = kAFill;
1572 }
1573
1574 ID3D11DeviceContext *context = nullptr;
1575 mD3D11Device->GetImmediateContext(&context);
1576 ASSERT_NE(context, nullptr);
1577
1578 D3D11_BOX dstBox = {0, 0, 0, bufferSize, bufferSize, 1};
1579 context->UpdateSubresource(d3d11Texture, arraySize - 1, &dstBox, imageData.data(),
1580 bufferSize * 4, imageData.size());
1581
1582 const EGLint attribs[] = {EGL_D3D11_TEXTURE_ARRAY_SLICE_ANGLE, arraySize - 1, EGL_NONE};
1583 EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1584 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1585 ASSERT_EGL_SUCCESS();
1586 ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1587
1588 GLuint texture;
1589 glGenTextures(1, &texture);
1590 glBindTexture(GL_TEXTURE_2D, texture);
1591 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1592 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1593 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1594 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1595 ASSERT_GL_NO_ERROR();
1596
1597 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1598 ASSERT_GL_NO_ERROR();
1599
1600 GLuint fbo;
1601 glGenFramebuffers(1, &fbo);
1602 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1603 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1604 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1605 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1606 ASSERT_GL_NO_ERROR();
1607
1608 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, kRFill,
1609 kGFill, kBFill, kAFill);
1610
1611 glDeleteFramebuffers(1, &fbo);
1612 glDeleteTextures(1, &texture);
1613 eglDestroyImageKHR(display, image);
1614
1615 d3d11Texture->Release();
1616 }
1617
1618 class D3DTextureYUVTest : public D3DTextureTest
1619 {
1620 protected:
CreateAndBindImageToTexture(EGLDisplay display,ID3D11Texture2D * d3d11Texture,EGLint plane,GLenum internalFormat,GLenum target,EGLImage * image,GLuint * texture)1621 void CreateAndBindImageToTexture(EGLDisplay display,
1622 ID3D11Texture2D *d3d11Texture,
1623 EGLint plane,
1624 GLenum internalFormat,
1625 GLenum target,
1626 EGLImage *image,
1627 GLuint *texture)
1628 {
1629 const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE,
1630 static_cast<EGLint>(internalFormat),
1631 EGL_D3D11_TEXTURE_PLANE_ANGLE, plane, EGL_NONE};
1632 *image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
1633 static_cast<EGLClientBuffer>(d3d11Texture), attribs);
1634 ASSERT_EGL_SUCCESS();
1635 ASSERT_NE(*image, EGL_NO_IMAGE_KHR);
1636
1637 // Create and bind Y plane texture to image.
1638 glGenTextures(1, texture);
1639 glActiveTexture(GL_TEXTURE0);
1640 glBindTexture(target, *texture);
1641 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1642 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1643 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1644 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1645 ASSERT_GL_NO_ERROR();
1646
1647 glEGLImageTargetTexture2DOES(target, *image);
1648 ASSERT_GL_NO_ERROR();
1649 }
1650
RunYUVSamplerTest(DXGI_FORMAT format)1651 void RunYUVSamplerTest(DXGI_FORMAT format)
1652 {
1653 ASSERT_TRUE(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
1654 format == DXGI_FORMAT_P016);
1655 UINT formatSupport;
1656 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
1657 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
1658 ASSERT_TRUE(formatSupport &
1659 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE));
1660
1661 const bool isNV12 = (format == DXGI_FORMAT_NV12);
1662 const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
1663 const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
1664 const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
1665
1666 constexpr char kVS[] =
1667 R"(precision highp float;
1668 attribute vec4 position;
1669 varying vec2 texcoord;
1670
1671 void main()
1672 {
1673 gl_Position = position;
1674 texcoord = (position.xy * 0.5) + 0.5;
1675 texcoord.y = 1.0 - texcoord.y;
1676 })";
1677
1678 constexpr char kFS[] =
1679 R"(#extension GL_OES_EGL_image_external : require
1680 precision highp float;
1681 uniform samplerExternalOES tex;
1682 varying vec2 texcoord;
1683
1684 void main()
1685 {
1686 gl_FragColor = texture2D(tex, texcoord);
1687 })";
1688
1689 GLuint program = CompileProgram(kVS, kFS);
1690 ASSERT_NE(0u, program) << "shader compilation failed.";
1691
1692 GLint textureLocation = glGetUniformLocation(program, "tex");
1693 ASSERT_NE(-1, textureLocation);
1694
1695 EGLWindow *window = getEGLWindow();
1696 EGLDisplay display = window->getDisplay();
1697
1698 window->makeCurrent();
1699
1700 const UINT bufferSize = 32;
1701 EXPECT_TRUE(mD3D11Device != nullptr);
1702 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
1703 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
1704 D3D11_BIND_SHADER_RESOURCE);
1705
1706 std::vector<unsigned char> imageData;
1707
1708 if (isNV12)
1709 {
1710 imageData.resize(bufferSize * bufferSize * 3 / 2);
1711 memset(imageData.data(), kYFillValue, bufferSize * bufferSize);
1712 const size_t kUVOffset = bufferSize * bufferSize;
1713 for (size_t i = 0; i < bufferSize * bufferSize / 2; i += 2)
1714 {
1715 imageData[kUVOffset + i] = kUFillValue;
1716 imageData[kUVOffset + i + 1] = kVFillValue;
1717 }
1718 }
1719 else
1720 {
1721 imageData.resize(bufferSize * bufferSize * 3);
1722 const size_t kUVOffset = bufferSize * bufferSize * 2;
1723 for (size_t i = 0; i < kUVOffset; i += 2)
1724 {
1725 imageData[i] = kYFillValue & 0xff;
1726 imageData[i + 1] = (kYFillValue >> 8) & 0xff;
1727 if (kUVOffset + i < imageData.size())
1728 {
1729 // Interleave U & V samples.
1730 const unsigned fill = (i % 4 == 0) ? kUFillValue : kVFillValue;
1731 imageData[kUVOffset + i] = fill & 0xff;
1732 imageData[kUVOffset + i + 1] = (fill >> 8) & 0xff;
1733 }
1734 }
1735 }
1736
1737 D3D11_SUBRESOURCE_DATA data = {};
1738 data.pSysMem = static_cast<const void *>(imageData.data());
1739 data.SysMemPitch = isNV12 ? bufferSize : bufferSize * 2;
1740
1741 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, &data, &d3d11Texture)));
1742
1743 // Create and bind Y plane texture to image.
1744 EGLImage yImage;
1745 GLuint yTexture;
1746
1747 GLenum internalFormat = format == DXGI_FORMAT_NV12 ? GL_RED_EXT : GL_R16_EXT;
1748 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat,
1749 GL_TEXTURE_EXTERNAL_OES, &yImage, &yTexture);
1750
1751 GLuint rbo;
1752 glGenRenderbuffers(1, &rbo);
1753 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
1754 glRenderbufferStorage(GL_RENDERBUFFER, isNV12 ? GL_RGBA8_OES : GL_RGBA16_EXT, bufferSize,
1755 bufferSize);
1756 ASSERT_GL_NO_ERROR();
1757
1758 GLuint fbo;
1759 glGenFramebuffers(1, &fbo);
1760 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1761 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
1762 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1763 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1764 ASSERT_GL_NO_ERROR();
1765
1766 // Draw the Y plane using a shader.
1767 glUseProgram(program);
1768 glUniform1i(textureLocation, 0);
1769 ASSERT_GL_NO_ERROR();
1770
1771 glViewport(0, 0, bufferSize, bufferSize);
1772 drawQuad(program, "position", 1.0f);
1773 ASSERT_GL_NO_ERROR();
1774
1775 if (isNV12)
1776 {
1777
1778 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
1779 kYFillValue, 0, 0, 0xff);
1780 }
1781 else
1782 {
1783 EXPECT_PIXEL_16UI(static_cast<GLint>(bufferSize) / 2,
1784 static_cast<GLint>(bufferSize) / 2, kYFillValue, 0, 0, 0xffff);
1785 }
1786 ASSERT_GL_NO_ERROR();
1787
1788 // Create and bind UV plane texture to image.
1789 EGLImage uvImage;
1790 GLuint uvTexture;
1791
1792 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
1793 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat,
1794 GL_TEXTURE_EXTERNAL_OES, &uvImage, &uvTexture);
1795
1796 // Draw the UV plane using a shader.
1797 glUseProgram(program);
1798 glUniform1i(textureLocation, 0);
1799 ASSERT_GL_NO_ERROR();
1800
1801 // Use only half of the framebuffer to match UV plane dimensions.
1802 glViewport(0, 0, bufferSize / 2, bufferSize / 2);
1803 drawQuad(program, "position", 1.0f);
1804 ASSERT_GL_NO_ERROR();
1805
1806 if (isNV12)
1807 {
1808
1809 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 4, static_cast<GLint>(bufferSize) / 4,
1810 kUFillValue, kVFillValue, 0, 0xff);
1811 }
1812 else
1813 {
1814 EXPECT_PIXEL_16UI(static_cast<GLint>(bufferSize) / 4,
1815 static_cast<GLint>(bufferSize) / 4, kUFillValue, kVFillValue, 0,
1816 0xffff);
1817 }
1818 ASSERT_GL_NO_ERROR();
1819
1820 glDeleteProgram(program);
1821 glDeleteTextures(1, &yTexture);
1822 glDeleteTextures(1, &uvTexture);
1823 glDeleteFramebuffers(1, &fbo);
1824 glDeleteRenderbuffers(1, &rbo);
1825 eglDestroyImageKHR(display, yImage);
1826 eglDestroyImageKHR(display, uvImage);
1827 }
1828
RunYUVRenderTest(DXGI_FORMAT format)1829 void RunYUVRenderTest(DXGI_FORMAT format)
1830 {
1831 ASSERT(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
1832 format == DXGI_FORMAT_P016);
1833 UINT formatSupport;
1834 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
1835 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
1836 ASSERT_TRUE(formatSupport &
1837 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET));
1838
1839 const bool isNV12 = (format == DXGI_FORMAT_NV12);
1840 const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
1841 const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
1842 const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
1843
1844 constexpr char kVS[] =
1845 R"(precision highp float;
1846 attribute vec4 position;
1847 varying vec2 texcoord;
1848
1849 void main()
1850 {
1851 gl_Position = position;
1852 texcoord = (position.xy * 0.5) + 0.5;
1853 texcoord.y = 1.0 - texcoord.y;
1854 })";
1855
1856 constexpr char kFS[] =
1857 R"(precision highp float;
1858 uniform vec4 color;
1859 varying vec2 texcoord;
1860
1861 void main()
1862 {
1863 gl_FragColor = color;
1864 })";
1865
1866 GLuint program = CompileProgram(kVS, kFS);
1867 ASSERT_NE(0u, program) << "shader compilation failed.";
1868
1869 GLint colorLocation = glGetUniformLocation(program, "color");
1870 ASSERT_NE(-1, colorLocation);
1871
1872 EGLWindow *window = getEGLWindow();
1873 EGLDisplay display = window->getDisplay();
1874
1875 window->makeCurrent();
1876
1877 const UINT bufferSize = 32;
1878 EXPECT_TRUE(mD3D11Device != nullptr);
1879 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
1880 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
1881 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1882
1883 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
1884
1885 // Create and bind Y plane texture to image.
1886 EGLImage yImage;
1887 GLuint yTexture;
1888
1889 GLenum internalFormat = format == DXGI_FORMAT_NV12 ? GL_RED_EXT : GL_R16_EXT;
1890 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat, GL_TEXTURE_2D,
1891 &yImage, &yTexture);
1892
1893 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, yImage);
1894 ASSERT_GL_NO_ERROR();
1895
1896 GLuint fbo;
1897 glGenFramebuffers(1, &fbo);
1898 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1899 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yTexture, 0);
1900 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1901 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1902 ASSERT_GL_NO_ERROR();
1903
1904 // Draw the Y plane using a shader.
1905 glUseProgram(program);
1906 glUniform4f(colorLocation, kYFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0, 0);
1907 ASSERT_GL_NO_ERROR();
1908
1909 drawQuad(program, "position", 1.0f);
1910 ASSERT_GL_NO_ERROR();
1911
1912 // Create and bind UV plane texture to image.
1913 EGLImage uvImage;
1914 GLuint uvTexture;
1915
1916 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
1917 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat, GL_TEXTURE_2D,
1918 &uvImage, &uvTexture);
1919
1920 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uvTexture, 0);
1921 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1922 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1923 ASSERT_GL_NO_ERROR();
1924
1925 // Draw the UV plane using a shader.
1926 glUseProgram(program);
1927 glUniform4f(colorLocation, kUFillValue * 1.0f / (isNV12 ? 0xff : 0xffff),
1928 kVFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0);
1929 ASSERT_GL_NO_ERROR();
1930
1931 drawQuad(program, "position", 1.0f);
1932 ASSERT_GL_NO_ERROR();
1933
1934 Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture;
1935 CD3D11_TEXTURE2D_DESC stagingDesc = desc;
1936 stagingDesc.BindFlags = 0;
1937 stagingDesc.Usage = D3D11_USAGE_STAGING;
1938 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1939
1940 EXPECT_TRUE(
1941 SUCCEEDED(mD3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture)));
1942
1943 Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
1944 mD3D11Device->GetImmediateContext(&context);
1945
1946 context->CopyResource(stagingTexture.Get(), d3d11Texture.Get());
1947 ASSERT_GL_NO_ERROR();
1948
1949 D3D11_MAPPED_SUBRESOURCE mapped = {};
1950 EXPECT_TRUE(SUCCEEDED(context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mapped)));
1951
1952 uint8_t *yPlane = reinterpret_cast<uint8_t *>(mapped.pData);
1953 uint8_t *uvPlane = yPlane + bufferSize * mapped.RowPitch;
1954 if (isNV12)
1955 {
1956 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue);
1957 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue);
1958 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], kVFillValue);
1959 }
1960 else
1961 {
1962 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue & 0xff);
1963 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2 + 1], (kYFillValue >> 8) & 0xff);
1964 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue & 0xff);
1965 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], (kUFillValue >> 8) & 0xff);
1966 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 2], kVFillValue & 0xff);
1967 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 3], (kVFillValue >> 8) & 0xff);
1968 }
1969
1970 context->Unmap(stagingTexture.Get(), 0);
1971
1972 glDeleteProgram(program);
1973 glDeleteTextures(1, &yTexture);
1974 glDeleteTextures(1, &uvTexture);
1975 glDeleteFramebuffers(1, &fbo);
1976 eglDestroyImageKHR(display, yImage);
1977 eglDestroyImageKHR(display, uvImage);
1978 }
1979
RunYUVReadPixelTest(DXGI_FORMAT format)1980 void RunYUVReadPixelTest(DXGI_FORMAT format)
1981 {
1982 ASSERT(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
1983 format == DXGI_FORMAT_P016);
1984 UINT formatSupport;
1985 ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
1986 FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
1987 ASSERT_TRUE(formatSupport &
1988 (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET));
1989
1990 const bool isNV12 = (format == DXGI_FORMAT_NV12);
1991 const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
1992 const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
1993 const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
1994
1995 constexpr char kVS[] =
1996 R"(precision highp float;
1997 attribute vec4 position;
1998 varying vec2 texcoord;
1999
2000 void main()
2001 {
2002 gl_Position = position;
2003 texcoord = (position.xy * 0.5) + 0.5;
2004 texcoord.y = 1.0 - texcoord.y;
2005 })";
2006
2007 constexpr char kFS[] =
2008 R"(precision highp float;
2009 uniform vec4 color;
2010 varying vec2 texcoord;
2011
2012 void main()
2013 {
2014 gl_FragColor = color;
2015 })";
2016
2017 GLuint program = CompileProgram(kVS, kFS);
2018 ASSERT_NE(0u, program) << "shader compilation failed.";
2019
2020 GLint colorLocation = glGetUniformLocation(program, "color");
2021 ASSERT_NE(-1, colorLocation);
2022
2023 EGLWindow *window = getEGLWindow();
2024 EGLDisplay display = window->getDisplay();
2025
2026 window->makeCurrent();
2027
2028 const UINT bufferSize = 32;
2029 EXPECT_TRUE(mD3D11Device != nullptr);
2030 Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11Texture;
2031 CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
2032 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
2033
2034 EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11Texture)));
2035
2036 // Create and bind Y plane texture to image.
2037 EGLImage yImage;
2038 GLuint yTexture;
2039
2040 GLenum internalFormat = format == DXGI_FORMAT_NV12 ? GL_RED_EXT : GL_R16_EXT;
2041 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 0, internalFormat, GL_TEXTURE_2D,
2042 &yImage, &yTexture);
2043
2044 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, yImage);
2045 ASSERT_GL_NO_ERROR();
2046
2047 GLuint fbo;
2048 glGenFramebuffers(1, &fbo);
2049 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2050 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yTexture, 0);
2051 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2052 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2053 ASSERT_GL_NO_ERROR();
2054
2055 // Draw the Y plane using a shader.
2056 glUseProgram(program);
2057 glUniform4f(colorLocation, kYFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0, 0);
2058 ASSERT_GL_NO_ERROR();
2059
2060 drawQuad(program, "position", 1.0f);
2061 ASSERT_GL_NO_ERROR();
2062
2063 // Read the Y plane pixels.
2064 if (isNV12)
2065 {
2066 GLubyte yPixels[4] = {};
2067 glReadPixels(0, bufferSize / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, yPixels);
2068 EXPECT_EQ(yPixels[0], kYFillValue);
2069 }
2070 else
2071 {
2072 GLushort yPixels[4] = {};
2073 glReadPixels(0, bufferSize / 2, 1, 1, GL_RGBA, GL_UNSIGNED_SHORT, yPixels);
2074 EXPECT_EQ(yPixels[0], kYFillValue);
2075 }
2076
2077 // Create and bind UV plane texture to image.
2078 EGLImage uvImage;
2079 GLuint uvTexture;
2080
2081 internalFormat = format == DXGI_FORMAT_NV12 ? GL_RG_EXT : GL_RG16_EXT;
2082 CreateAndBindImageToTexture(display, d3d11Texture.Get(), 1, internalFormat, GL_TEXTURE_2D,
2083 &uvImage, &uvTexture);
2084
2085 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uvTexture, 0);
2086 EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
2087 static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
2088 ASSERT_GL_NO_ERROR();
2089
2090 // Draw the UV plane using a shader.
2091 glUseProgram(program);
2092 glUniform4f(colorLocation, kUFillValue * 1.0f / (isNV12 ? 0xff : 0xffff),
2093 kVFillValue * 1.0f / (isNV12 ? 0xff : 0xffff), 0, 0);
2094 ASSERT_GL_NO_ERROR();
2095
2096 drawQuad(program, "position", 1.0f);
2097 ASSERT_GL_NO_ERROR();
2098
2099 // Read the UV plane pixels.
2100 if (isNV12)
2101 {
2102 GLubyte uvPixels[4] = {};
2103 glReadPixels(0, bufferSize / 4, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, uvPixels);
2104 EXPECT_EQ(uvPixels[0], kUFillValue);
2105 EXPECT_EQ(uvPixels[1], kVFillValue);
2106 }
2107 else
2108 {
2109 GLushort uvPixels[4] = {};
2110 glReadPixels(0, bufferSize / 4, 1, 1, GL_RGBA, GL_UNSIGNED_SHORT, uvPixels);
2111 EXPECT_EQ(uvPixels[0], kUFillValue);
2112 EXPECT_EQ(uvPixels[1], kVFillValue);
2113 }
2114
2115 Microsoft::WRL::ComPtr<ID3D11Texture2D> stagingTexture;
2116 CD3D11_TEXTURE2D_DESC stagingDesc = desc;
2117 stagingDesc.BindFlags = 0;
2118 stagingDesc.Usage = D3D11_USAGE_STAGING;
2119 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
2120
2121 EXPECT_TRUE(
2122 SUCCEEDED(mD3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture)));
2123
2124 Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
2125 mD3D11Device->GetImmediateContext(&context);
2126
2127 context->CopyResource(stagingTexture.Get(), d3d11Texture.Get());
2128 ASSERT_GL_NO_ERROR();
2129
2130 D3D11_MAPPED_SUBRESOURCE mapped = {};
2131 EXPECT_TRUE(SUCCEEDED(context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mapped)));
2132
2133 uint8_t *yPlane = reinterpret_cast<uint8_t *>(mapped.pData);
2134 uint8_t *uvPlane = yPlane + bufferSize * mapped.RowPitch;
2135 if (isNV12)
2136 {
2137 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue);
2138 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue);
2139 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], kVFillValue);
2140 }
2141 else
2142 {
2143 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2], kYFillValue & 0xff);
2144 EXPECT_EQ(yPlane[mapped.RowPitch * bufferSize / 2 + 1], (kYFillValue >> 8) & 0xff);
2145 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4], kUFillValue & 0xff);
2146 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 1], (kUFillValue >> 8) & 0xff);
2147 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 2], kVFillValue & 0xff);
2148 EXPECT_EQ(uvPlane[mapped.RowPitch * bufferSize / 4 + 3], (kVFillValue >> 8) & 0xff);
2149 }
2150
2151 context->Unmap(stagingTexture.Get(), 0);
2152
2153 glDeleteProgram(program);
2154 glDeleteTextures(1, &yTexture);
2155 glDeleteTextures(1, &uvTexture);
2156 glDeleteFramebuffers(1, &fbo);
2157 eglDestroyImageKHR(display, yImage);
2158 eglDestroyImageKHR(display, uvImage);
2159 }
2160 };
2161
2162 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and the resulting GL
2163 // textures can be sampled from.
TEST_P(D3DTextureYUVTest,NV12TextureImageSampler)2164 TEST_P(D3DTextureYUVTest, NV12TextureImageSampler)
2165 {
2166 RunYUVSamplerTest(DXGI_FORMAT_NV12);
2167 }
2168
2169 // ANGLE ES2/D3D11 supports GL_EXT_texture_norm16 even though the extension spec says it's ES3 only.
2170 // Test P010 on ES2 since Chromium's Skia context is ES2 and it uses P010 for HDR video playback.
TEST_P(D3DTextureYUVTest,P010TextureImageSampler)2171 TEST_P(D3DTextureYUVTest, P010TextureImageSampler)
2172 {
2173 RunYUVSamplerTest(DXGI_FORMAT_P010);
2174 }
2175
2176 // Same as above, but for P016. P016 doesn't seem to be supported on all GPUs so it might be skipped
2177 // more often than P010 and NV12 e.g. on the NVIDIA GTX 1050 Ti.
TEST_P(D3DTextureYUVTest,P016TextureImageSampler)2178 TEST_P(D3DTextureYUVTest, P016TextureImageSampler)
2179 {
2180 RunYUVSamplerTest(DXGI_FORMAT_P016);
2181 }
2182
2183 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and rendered to as
2184 // framebuffer attachments.
TEST_P(D3DTextureYUVTest,NV12TextureImageRender)2185 TEST_P(D3DTextureYUVTest, NV12TextureImageRender)
2186 {
2187 RunYUVRenderTest(DXGI_FORMAT_NV12);
2188 }
2189
2190 // ANGLE ES2/D3D11 supports GL_EXT_texture_norm16 even though the extension spec says it's ES3 only.
2191 // Test P010 on ES2 since Chromium's Skia context is ES2 and it uses P010 for HDR video playback.
TEST_P(D3DTextureYUVTest,P010TextureImageRender)2192 TEST_P(D3DTextureYUVTest, P010TextureImageRender)
2193 {
2194 RunYUVRenderTest(DXGI_FORMAT_P010);
2195 }
2196
2197 // Same as above, but for P016. P016 doesn't seem to be supported on all GPUs so it might be skipped
2198 // more often than P010 and NV12 e.g. on the NVIDIA GTX 1050 Ti.
TEST_P(D3DTextureYUVTest,P016TextureImageRender)2199 TEST_P(D3DTextureYUVTest, P016TextureImageRender)
2200 {
2201 RunYUVRenderTest(DXGI_FORMAT_P016);
2202 }
2203
2204 // Test that an NV12 D3D11 texture can be imported as two R8 and RG8 EGLImages and rendered to as
2205 // framebuffer attachments and then read from as individual planes.
TEST_P(D3DTextureYUVTest,NV12TextureImageReadPixel)2206 TEST_P(D3DTextureYUVTest, NV12TextureImageReadPixel)
2207 {
2208 RunYUVReadPixelTest(DXGI_FORMAT_NV12);
2209 }
2210
2211 // ANGLE ES2/D3D11 supports GL_EXT_texture_norm16 even though the extension spec says it's ES3 only.
2212 // Test P010 on ES2 since Chromium's Skia context is ES2 and it uses P010 for HDR video playback.
TEST_P(D3DTextureYUVTest,P010TextureImageReadPixel)2213 TEST_P(D3DTextureYUVTest, P010TextureImageReadPixel)
2214 {
2215 RunYUVReadPixelTest(DXGI_FORMAT_P010);
2216 }
2217
2218 // Same as above, but for P016. P016 doesn't seem to be supported on all GPUs so it might be skipped
2219 // more often than P010 and NV12 e.g. on the NVIDIA GTX 1050 Ti.
TEST_P(D3DTextureYUVTest,P016TextureImageReadPixel)2220 TEST_P(D3DTextureYUVTest, P016TextureImageReadPixel)
2221 {
2222 RunYUVReadPixelTest(DXGI_FORMAT_P016);
2223 }
2224
2225 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
2226 // tests should be run against.
2227 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureTest);
2228 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureClearTest);
2229 ANGLE_INSTANTIATE_TEST_ES2(D3DTextureYUVTest);
2230 ANGLE_INSTANTIATE_TEST_ES3(D3DTextureTestES3);
2231 // D3D Debug device reports an error. http://anglebug.com/3513
2232 // ANGLE_INSTANTIATE_TEST(D3DTextureTestMS, ES2_D3D11());
2233 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(D3DTextureTestMS);
2234 } // namespace angle
2235