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
11 #include <d3d11.h>
12 #include <windows.h>
13
14 #include "com_utils.h"
15
16 namespace angle
17 {
18
19 class D3DTextureTest : public ANGLETest
20 {
21 protected:
D3DTextureTest()22 D3DTextureTest()
23 {
24 setWindowWidth(128);
25 setWindowHeight(128);
26 setConfigRedBits(8);
27 setConfigGreenBits(8);
28 setConfigBlueBits(8);
29 setConfigAlphaBits(8);
30 }
31
SetUp()32 void SetUp() override
33 {
34 ANGLETest::SetUp();
35
36 // clang-format off
37 const std::string vsSource = SHADER_SOURCE
38 (
39 precision highp float;
40 attribute vec4 position;
41 varying vec2 texcoord;
42
43 void main()
44 {
45 gl_Position = position;
46 texcoord = (position.xy * 0.5) + 0.5;
47 texcoord.y = 1.0 - texcoord.y;
48 }
49 );
50
51 const std::string textureFSSource = SHADER_SOURCE
52 (
53 precision highp float;
54 uniform sampler2D tex;
55 varying vec2 texcoord;
56
57 void main()
58 {
59 gl_FragColor = texture2D(tex, texcoord);
60 }
61 );
62 // clang-format on
63
64 mTextureProgram = CompileProgram(vsSource, textureFSSource);
65 ASSERT_NE(0u, mTextureProgram) << "shader compilation failed.";
66
67 mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
68 ASSERT_NE(-1, mTextureUniformLocation);
69
70 mD3D11Module = LoadLibrary(TEXT("d3d11.dll"));
71 ASSERT_NE(nullptr, mD3D11Module);
72
73 PFN_D3D11_CREATE_DEVICE createDeviceFunc = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
74 GetProcAddress(mD3D11Module, "D3D11CreateDevice"));
75
76 EGLWindow *window = getEGLWindow();
77 EGLDisplay display = window->getDisplay();
78 if (eglDisplayExtensionEnabled(display, "EGL_EXT_device_query"))
79 {
80 PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT =
81 reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
82 eglGetProcAddress("eglQueryDisplayAttribEXT"));
83 PFNEGLQUERYDEVICEATTRIBEXTPROC eglQueryDeviceAttribEXT =
84 reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(
85 eglGetProcAddress("eglQueryDeviceAttribEXT"));
86
87 EGLDeviceEXT device = 0;
88 {
89 EGLAttrib result = 0;
90 EXPECT_EGL_TRUE(eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, &result));
91 device = reinterpret_cast<EGLDeviceEXT>(result);
92 }
93
94 if (eglDeviceExtensionEnabled(device, "EGL_ANGLE_device_d3d"))
95 {
96 EGLAttrib result = 0;
97 if (eglQueryDeviceAttribEXT(device, EGL_D3D11_DEVICE_ANGLE, &result))
98 {
99 mD3D11Device = reinterpret_cast<ID3D11Device *>(result);
100 mD3D11Device->AddRef();
101 }
102 else if (eglQueryDeviceAttribEXT(device, EGL_D3D9_DEVICE_ANGLE, &result))
103 {
104 mD3D9Device = reinterpret_cast<IDirect3DDevice9 *>(result);
105 mD3D9Device->AddRef();
106 }
107 }
108 }
109 else
110 {
111 ASSERT_TRUE(
112 SUCCEEDED(createDeviceFunc(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr,
113 0, D3D11_SDK_VERSION, &mD3D11Device, nullptr, nullptr)));
114 }
115 }
116
TearDown()117 void TearDown() override
118 {
119 glDeleteProgram(mTextureProgram);
120
121 if (mD3D11Device)
122 {
123 mD3D11Device->Release();
124 mD3D11Device = nullptr;
125 }
126
127 FreeLibrary(mD3D11Module);
128 mD3D11Module = nullptr;
129
130 if (mD3D9Device)
131 {
132 mD3D9Device->Release();
133 mD3D9Device = nullptr;
134 }
135
136 ANGLETest::TearDown();
137 }
138
createPBuffer(size_t width,size_t height,EGLint eglTextureFormat,EGLint eglTextureTarget)139 EGLSurface createPBuffer(size_t width,
140 size_t height,
141 EGLint eglTextureFormat,
142 EGLint eglTextureTarget)
143 {
144 EGLWindow *window = getEGLWindow();
145 EGLDisplay display = window->getDisplay();
146 EGLConfig config = window->getConfig();
147
148 EGLint attribs[] = {
149 EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET,
150 eglTextureTarget, EGL_NONE, EGL_NONE,
151 };
152
153 if (mD3D11Device)
154 {
155 ID3D11Texture2D *texture = nullptr;
156 CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, static_cast<UINT>(width),
157 static_cast<UINT>(height), 1, 1,
158 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
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 else if (mD3D9Device)
169 {
170 IDirect3DTexture9 *texture = nullptr;
171 EXPECT_TRUE(SUCCEEDED(mD3D9Device->CreateTexture(
172 static_cast<UINT>(width), static_cast<UINT>(height), 1, D3DUSAGE_RENDERTARGET,
173 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, nullptr)));
174
175 EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
176 texture, config, attribs);
177
178 texture->Release();
179
180 return pbuffer;
181 }
182 else
183 {
184 return EGL_NO_SURFACE;
185 }
186 }
187
valid() const188 bool valid() const
189 {
190 EGLWindow *window = getEGLWindow();
191 EGLDisplay display = window->getDisplay();
192 if (!eglDisplayExtensionEnabled(display, "EGL_ANGLE_d3d_texture_client_buffer"))
193 {
194 std::cout << "Test skipped due to missing EGL_ANGLE_d3d_texture_client_buffer"
195 << std::endl;
196 return false;
197 }
198
199 if (!mD3D11Device && !mD3D9Device)
200 {
201 std::cout << "Test skipped due to no D3D devices being available." << std::endl;
202 return false;
203 }
204
205 if (IsWindows() && IsAMD() && IsOpenGL())
206 {
207 std::cout << "Test skipped on Windows AMD OpenGL." << std::endl;
208 return false;
209 }
210
211 if (IsWindows() && IsIntel() && IsOpenGL())
212 {
213 std::cout << "Test skipped on Windows Intel OpenGL." << std::endl;
214 return false;
215 }
216 return true;
217 }
218
219 GLuint mTextureProgram;
220 GLint mTextureUniformLocation;
221
222 HMODULE mD3D11Module = nullptr;
223 ID3D11Device *mD3D11Device = nullptr;
224
225 IDirect3DDevice9 *mD3D9Device = nullptr;
226 };
227
228 // Test creating a pbuffer from a d3d surface and clearing it
TEST_P(D3DTextureTest,Clear)229 TEST_P(D3DTextureTest, Clear)
230 {
231 if (!valid())
232 {
233 return;
234 }
235
236 EGLWindow *window = getEGLWindow();
237 EGLDisplay display = window->getDisplay();
238
239 const size_t bufferSize = 32;
240
241 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE);
242 ASSERT_EGL_SUCCESS();
243 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
244
245 // Apply the Pbuffer and clear it to purple and verify
246 eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
247 ASSERT_EGL_SUCCESS();
248
249 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
250 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
251 glClear(GL_COLOR_BUFFER_BIT);
252 ASSERT_GL_NO_ERROR();
253 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
254 255, 255);
255
256 eglDestroySurface(display, pbuffer);
257 }
258
259 // Test creating a pbuffer from a d3d surface and binding it to a texture
TEST_P(D3DTextureTest,BindTexImage)260 TEST_P(D3DTextureTest, BindTexImage)
261 {
262 if (!valid())
263 {
264 return;
265 }
266
267 EGLWindow *window = getEGLWindow();
268
269 const size_t bufferSize = 32;
270
271 EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D);
272 ASSERT_EGL_SUCCESS();
273 ASSERT_NE(pbuffer, EGL_NO_SURFACE);
274
275 // Apply the Pbuffer and clear it to purple
276 eglMakeCurrent(window->getDisplay(), pbuffer, pbuffer, window->getContext());
277 ASSERT_EGL_SUCCESS();
278
279 glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
280 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
281 glClear(GL_COLOR_BUFFER_BIT);
282 ASSERT_GL_NO_ERROR();
283
284 EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0,
285 255, 255);
286
287 // Apply the window surface
288 eglMakeCurrent(window->getDisplay(), window->getSurface(), window->getSurface(),
289 window->getContext());
290
291 // Create a texture and bind the Pbuffer to it
292 GLuint texture = 0;
293 glGenTextures(1, &texture);
294 glBindTexture(GL_TEXTURE_2D, texture);
295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
296 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
297 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
298 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
299 EXPECT_GL_NO_ERROR();
300
301 eglBindTexImage(window->getDisplay(), pbuffer, EGL_BACK_BUFFER);
302 glViewport(0, 0, getWindowWidth(), getWindowHeight());
303 ASSERT_EGL_SUCCESS();
304
305 // Draw a quad and verify that it is purple
306 glUseProgram(mTextureProgram);
307 glUniform1i(mTextureUniformLocation, 0);
308
309 drawQuad(mTextureProgram, "position", 0.5f);
310 EXPECT_GL_NO_ERROR();
311
312 // Unbind the texture
313 eglReleaseTexImage(window->getDisplay(), pbuffer, EGL_BACK_BUFFER);
314 ASSERT_EGL_SUCCESS();
315
316 // Verify that purple was drawn
317 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255);
318
319 glDeleteTextures(1, &texture);
320 }
321
322 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
323 // tests should be run against.
324 ANGLE_INSTANTIATE_TEST(D3DTextureTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
325
326 } // namespace
327