xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 
7 #include "test_utils/ANGLETest.h"
8 
9 #include <d3d11.h>
10 #include <cstdint>
11 
12 #include "util/OSWindow.h"
13 #include "util/com_utils.h"
14 
15 using namespace angle;
16 
17 class EGLPresentPathD3D11 : public ANGLETest<>
18 {
19   protected:
EGLPresentPathD3D11()20     EGLPresentPathD3D11()
21         : mDisplay(EGL_NO_DISPLAY),
22           mContext(EGL_NO_CONTEXT),
23           mSurface(EGL_NO_SURFACE),
24           mOffscreenSurfaceD3D11Texture(nullptr),
25           mConfig(0),
26           mOSWindow(nullptr),
27           mWindowWidth(0)
28     {}
29 
testSetUp()30     void testSetUp() override
31     {
32         mOSWindow    = OSWindow::New();
33         mWindowWidth = 64;
34         mOSWindow->initialize("EGLPresentPathD3D11", mWindowWidth, mWindowWidth);
35     }
36 
initializeEGL(bool usePresentPathFast)37     void initializeEGL(bool usePresentPathFast)
38     {
39         int clientVersion = GetParam().majorVersion;
40 
41         // Set up EGL Display
42         EGLint displayAttribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE,
43                                    GetParam().getRenderer(),
44                                    EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
45                                    GetParam().eglParameters.majorVersion,
46                                    EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
47                                    GetParam().eglParameters.majorVersion,
48                                    EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
49                                    usePresentPathFast ? EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE
50                                                       : EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE,
51                                    EGL_NONE};
52         mDisplay =
53             eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttribs);
54         ASSERT_TRUE(EGL_NO_DISPLAY != mDisplay);
55         ASSERT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
56 
57         // Choose the EGL config
58         EGLint numConfigs;
59         EGLint configAttribs[] = {EGL_RED_SIZE,
60                                   8,
61                                   EGL_GREEN_SIZE,
62                                   8,
63                                   EGL_BLUE_SIZE,
64                                   8,
65                                   EGL_ALPHA_SIZE,
66                                   8,
67                                   EGL_RENDERABLE_TYPE,
68                                   clientVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,
69                                   EGL_SURFACE_TYPE,
70                                   EGL_PBUFFER_BIT,
71                                   EGL_NONE};
72         ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs));
73         ASSERT_EQ(1, numConfigs);
74 
75         // Set up the EGL context
76         EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, clientVersion, EGL_NONE};
77         mContext                = eglCreateContext(mDisplay, mConfig, nullptr, contextAttribs);
78         ASSERT_TRUE(EGL_NO_CONTEXT != mContext);
79     }
80 
createWindowSurface()81     void createWindowSurface()
82     {
83         mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
84     }
85 
createPbufferFromClientBufferSurface()86     void createPbufferFromClientBufferSurface()
87     {
88         EGLAttrib device      = 0;
89         EGLAttrib angleDevice = 0;
90 
91         EXPECT_TRUE(IsEGLClientExtensionEnabled("EGL_EXT_device_query"));
92 
93         ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &angleDevice));
94         ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),
95                                                 EGL_D3D11_DEVICE_ANGLE, &device));
96         ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device);
97 
98         D3D11_TEXTURE2D_DESC textureDesc = {0};
99         textureDesc.Width                = mWindowWidth;
100         textureDesc.Height               = mWindowWidth;
101         textureDesc.Format               = DXGI_FORMAT_B8G8R8A8_UNORM;
102         textureDesc.MipLevels            = 1;
103         textureDesc.ArraySize            = 1;
104         textureDesc.SampleDesc.Count     = 1;
105         textureDesc.SampleDesc.Quality   = 0;
106         textureDesc.Usage                = D3D11_USAGE_DEFAULT;
107         textureDesc.BindFlags            = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
108         textureDesc.CPUAccessFlags       = 0;
109         textureDesc.MiscFlags            = D3D11_RESOURCE_MISC_SHARED;
110 
111         ASSERT_TRUE(SUCCEEDED(
112             d3d11Device->CreateTexture2D(&textureDesc, nullptr, &mOffscreenSurfaceD3D11Texture)));
113 
114         IDXGIResource *dxgiResource =
115             DynamicCastComObject<IDXGIResource>(mOffscreenSurfaceD3D11Texture);
116         ASSERT_NE(nullptr, dxgiResource);
117 
118         HANDLE sharedHandle = 0;
119         ASSERT_TRUE(SUCCEEDED(dxgiResource->GetSharedHandle(&sharedHandle)));
120         SafeRelease(dxgiResource);
121 
122         EGLint pBufferAttributes[] = {EGL_WIDTH,          mWindowWidth,       EGL_HEIGHT,
123                                       mWindowWidth,       EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
124                                       EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,   EGL_NONE};
125 
126         mSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
127                                                     sharedHandle, mConfig, pBufferAttributes);
128         ASSERT_TRUE(EGL_NO_SURFACE != mSurface);
129     }
130 
makeCurrent()131     void makeCurrent() { ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)); }
132 
testTearDown()133     void testTearDown() override
134     {
135         SafeRelease(mOffscreenSurfaceD3D11Texture);
136 
137         if (mDisplay != EGL_NO_DISPLAY)
138         {
139             eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
140 
141             if (mSurface != EGL_NO_SURFACE)
142             {
143                 eglDestroySurface(mDisplay, mSurface);
144                 mSurface = EGL_NO_SURFACE;
145             }
146 
147             if (mContext != EGL_NO_CONTEXT)
148             {
149                 ASSERT_EGL_TRUE(
150                     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
151                 eglDestroyContext(mDisplay, mContext);
152                 mContext = EGL_NO_CONTEXT;
153             }
154 
155             eglTerminate(mDisplay);
156             mDisplay = EGL_NO_DISPLAY;
157         }
158 
159         mOSWindow->destroy();
160         OSWindow::Delete(&mOSWindow);
161     }
162 
drawQuadUsingGL()163     void drawQuadUsingGL()
164     {
165         GLuint m2DProgram;
166         GLint mTexture2DUniformLocation;
167 
168         constexpr char kVS[] =
169             R"(precision highp float;
170             attribute vec4 position;
171             varying vec2 texcoord;
172 
173             void main()
174             {
175                 gl_Position = vec4(position.xy, 0.0, 1.0);
176                 texcoord = (position.xy * 0.5) + 0.5;
177             })";
178 
179         constexpr char kFS[] =
180             R"(precision highp float;
181             uniform sampler2D tex;
182             varying vec2 texcoord;
183 
184             void main()
185             {
186                 gl_FragColor = texture2D(tex, texcoord);
187             })";
188 
189         m2DProgram                = CompileProgram(kVS, kFS);
190         mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex");
191 
192         uint8_t textureInitData[16] = {
193             255, 0,   0,   255,  // Red
194             0,   255, 0,   255,  // Green
195             0,   0,   255, 255,  // Blue
196             255, 255, 0,   255   // Red + Green
197         };
198 
199         // Create a simple RGBA texture
200         GLuint tex = 0;
201         glGenTextures(1, &tex);
202         glBindTexture(GL_TEXTURE_2D, tex);
203         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
204                      textureInitData);
205         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
206         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
207         ASSERT_GL_NO_ERROR();
208 
209         // Draw a quad using the texture
210         glClear(GL_COLOR_BUFFER_BIT);
211         glUseProgram(m2DProgram);
212         glUniform1i(mTexture2DUniformLocation, 0);
213 
214         GLint positionLocation = glGetAttribLocation(m2DProgram, "position");
215         glUseProgram(m2DProgram);
216         const GLfloat vertices[] = {
217             -1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
218             -1.0f, 1.0f, 0.5f, 1.0f,  -1.0f, 0.5f, 1.0f, 1.0f,  0.5f,
219         };
220 
221         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
222         glEnableVertexAttribArray(positionLocation);
223 
224         glDrawArrays(GL_TRIANGLES, 0, 6);
225         ASSERT_GL_NO_ERROR();
226 
227         glDeleteProgram(m2DProgram);
228     }
229 
checkPixelsUsingGL()230     void checkPixelsUsingGL()
231     {
232         // Note that the texture is in BGRA format
233         EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);                                  // Red
234         EXPECT_PIXEL_EQ(mWindowWidth - 1, 0, 0, 255, 0, 255);                   // Green
235         EXPECT_PIXEL_EQ(0, mWindowWidth - 1, 0, 0, 255, 255);                   // Blue
236         EXPECT_PIXEL_EQ(mWindowWidth - 1, mWindowWidth - 1, 255, 255, 0, 255);  // Red + green
237     }
238 
checkPixelsUsingD3D(bool usingPresentPathFast)239     void checkPixelsUsingD3D(bool usingPresentPathFast)
240     {
241         ASSERT_NE(nullptr, mOffscreenSurfaceD3D11Texture);
242 
243         D3D11_TEXTURE2D_DESC textureDesc = {0};
244         ID3D11Device *device;
245         ID3D11DeviceContext *context;
246         mOffscreenSurfaceD3D11Texture->GetDesc(&textureDesc);
247         mOffscreenSurfaceD3D11Texture->GetDevice(&device);
248         device->GetImmediateContext(&context);
249         ASSERT_NE(nullptr, device);
250         ASSERT_NE(nullptr, context);
251 
252         textureDesc.CPUAccessFlags  = D3D11_CPU_ACCESS_READ;
253         textureDesc.Usage           = D3D11_USAGE_STAGING;
254         textureDesc.BindFlags       = 0;
255         textureDesc.MiscFlags       = 0;
256         ID3D11Texture2D *cpuTexture = nullptr;
257         ASSERT_TRUE(SUCCEEDED(device->CreateTexture2D(&textureDesc, nullptr, &cpuTexture)));
258 
259         context->CopyResource(cpuTexture, mOffscreenSurfaceD3D11Texture);
260 
261         D3D11_MAPPED_SUBRESOURCE mappedSubresource;
262         context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource);
263         ASSERT_EQ(static_cast<UINT>(mWindowWidth * 4), mappedSubresource.RowPitch);
264         ASSERT_EQ(static_cast<UINT>(mWindowWidth * mWindowWidth * 4), mappedSubresource.DepthPitch);
265 
266         angle::GLColor *byteData = reinterpret_cast<angle::GLColor *>(mappedSubresource.pData);
267 
268         // Note that the texture is in BGRA format, although the GLColor struct is RGBA
269         GLColor expectedTopLeftPixel     = GLColor(0, 0, 255, 255);    // Red
270         GLColor expectedTopRightPixel    = GLColor(0, 255, 0, 255);    // Green
271         GLColor expectedBottomLeftPixel  = GLColor(255, 0, 0, 255);    // Blue
272         GLColor expectedBottomRightPixel = GLColor(0, 255, 255, 255);  // Red + Green
273 
274         if (usingPresentPathFast)
275         {
276             // Invert the expected values
277             GLColor tempTopLeft      = expectedTopLeftPixel;
278             GLColor tempTopRight     = expectedTopRightPixel;
279             expectedTopLeftPixel     = expectedBottomLeftPixel;
280             expectedTopRightPixel    = expectedBottomRightPixel;
281             expectedBottomLeftPixel  = tempTopLeft;
282             expectedBottomRightPixel = tempTopRight;
283         }
284 
285         EXPECT_EQ(expectedTopLeftPixel, byteData[0]);
286         EXPECT_EQ(expectedTopRightPixel, byteData[(mWindowWidth - 1)]);
287         EXPECT_EQ(expectedBottomLeftPixel, byteData[(mWindowWidth - 1) * mWindowWidth]);
288         EXPECT_EQ(expectedBottomRightPixel,
289                   byteData[(mWindowWidth - 1) * mWindowWidth + (mWindowWidth - 1)]);
290 
291         context->Unmap(cpuTexture, 0);
292         SafeRelease(cpuTexture);
293         SafeRelease(device);
294         SafeRelease(context);
295     }
296 
297     EGLDisplay mDisplay;
298     EGLContext mContext;
299     EGLSurface mSurface;
300     ID3D11Texture2D *mOffscreenSurfaceD3D11Texture;
301     EGLConfig mConfig;
302     OSWindow *mOSWindow;
303     GLint mWindowWidth;
304 };
305 
306 // Test that rendering basic content onto a window surface when present path fast
307 // is enabled works as expected
TEST_P(EGLPresentPathD3D11,WindowPresentPathFast)308 TEST_P(EGLPresentPathD3D11, WindowPresentPathFast)
309 {
310     initializeEGL(true);
311     createWindowSurface();
312     makeCurrent();
313 
314     drawQuadUsingGL();
315 
316     checkPixelsUsingGL();
317 }
318 
319 // Test that rendering basic content onto a client buffer surface when present path fast
320 // works as expected, and is also oriented the correct way around
TEST_P(EGLPresentPathD3D11,ClientBufferPresentPathFast)321 TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathFast)
322 {
323     initializeEGL(true);
324     createPbufferFromClientBufferSurface();
325     makeCurrent();
326 
327     drawQuadUsingGL();
328 
329     checkPixelsUsingGL();
330     checkPixelsUsingD3D(true);
331 }
332 
333 // Test that rendering basic content onto a window surface when present path fast
334 // is disabled works as expected
TEST_P(EGLPresentPathD3D11,WindowPresentPathCopy)335 TEST_P(EGLPresentPathD3D11, WindowPresentPathCopy)
336 {
337     initializeEGL(false);
338     createWindowSurface();
339     makeCurrent();
340 
341     drawQuadUsingGL();
342 
343     checkPixelsUsingGL();
344 }
345 
346 // Test that rendering basic content onto a client buffer surface when present path
347 // fast is disabled works as expected, and is also oriented the correct way around
TEST_P(EGLPresentPathD3D11,ClientBufferPresentPathCopy)348 TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathCopy)
349 {
350     initializeEGL(false);
351     createPbufferFromClientBufferSurface();
352     makeCurrent();
353 
354     drawQuadUsingGL();
355 
356     checkPixelsUsingGL();
357     checkPixelsUsingD3D(false);
358 }
359 
360 ANGLE_INSTANTIATE_TEST(EGLPresentPathD3D11, WithNoFixture(ES2_D3D11()));
361