1 //
2 // Copyright 2014 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 // DisplayD3D.cpp: D3D implementation of egl::Display
8 
9 #include "libANGLE/renderer/d3d/DisplayD3D.h"
10 
11 #include <EGL/eglext.h>
12 
13 #include "libANGLE/Config.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Display.h"
16 #include "libANGLE/Surface.h"
17 #include "libANGLE/Thread.h"
18 #include "libANGLE/histogram_macros.h"
19 #include "libANGLE/renderer/d3d/DeviceD3D.h"
20 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
21 #include "libANGLE/renderer/d3d/RendererD3D.h"
22 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
23 #include "libANGLE/renderer/d3d/SwapChainD3D.h"
24 
25 #if !defined(ANGLE_DEFAULT_D3D11)
26 // Enables use of the Direct3D 11 API for a default display, when available
27 #    define ANGLE_DEFAULT_D3D11 1
28 #endif
29 
30 namespace rx
31 {
32 
33 using CreateRendererD3DFunction = RendererD3D *(*)(egl::Display *);
34 
CreateRendererD3D(egl::Display * display,RendererD3D ** outRenderer)35 egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
36 {
37     ASSERT(outRenderer != nullptr);
38 
39     std::vector<CreateRendererD3DFunction> rendererCreationFunctions;
40 
41     if (display->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
42     {
43         const auto &attribMap              = display->getAttributeMap();
44         EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
45 
46         EGLint requestedDisplayType = static_cast<EGLint>(
47             attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
48 
49 #if defined(ANGLE_ENABLE_D3D11)
50         const auto addD3D11 = nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
51                               nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE ||
52                               requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
53 #endif
54 
55 #if defined(ANGLE_ENABLE_D3D9)
56         const auto addD3D9 = nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
57                              requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
58 #endif
59 
60 #if ANGLE_DEFAULT_D3D11
61 #    if defined(ANGLE_ENABLE_D3D11)
62         if (addD3D11)
63         {
64             rendererCreationFunctions.push_back(CreateRenderer11);
65         }
66 #    endif
67 
68 #    if defined(ANGLE_ENABLE_D3D9)
69         if (addD3D9)
70         {
71             rendererCreationFunctions.push_back(CreateRenderer9);
72         }
73 #    endif
74 #else
75 #    if defined(ANGLE_ENABLE_D3D9)
76         if (addD3D9)
77         {
78             rendererCreationFunctions.push_back(CreateRenderer9);
79         }
80 #    endif
81 
82 #    if defined(ANGLE_ENABLE_D3D11)
83         if (addD3D11)
84         {
85             rendererCreationFunctions.push_back(CreateRenderer11);
86         }
87 #    endif
88 #endif
89 
90         if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
91             nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
92             requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
93         {
94             // The default display is requested, try the D3D9 and D3D11 renderers, order them using
95             // the definition of ANGLE_DEFAULT_D3D11
96 #if ANGLE_DEFAULT_D3D11
97 #    if defined(ANGLE_ENABLE_D3D11)
98             rendererCreationFunctions.push_back(CreateRenderer11);
99 #    endif
100 #    if defined(ANGLE_ENABLE_D3D9)
101             rendererCreationFunctions.push_back(CreateRenderer9);
102 #    endif
103 #else
104 #    if defined(ANGLE_ENABLE_D3D9)
105             rendererCreationFunctions.push_back(CreateRenderer9);
106 #    endif
107 #    if defined(ANGLE_ENABLE_D3D11)
108             rendererCreationFunctions.push_back(CreateRenderer11);
109 #    endif
110 #endif
111         }
112     }
113     else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
114     {
115 #if defined(ANGLE_ENABLE_D3D11)
116         if (display->getDevice()->getType() == EGL_D3D11_DEVICE_ANGLE)
117         {
118             rendererCreationFunctions.push_back(CreateRenderer11);
119         }
120 #endif
121     }
122     else
123     {
124         UNIMPLEMENTED();
125     }
126 
127     for (size_t i = 0; i < rendererCreationFunctions.size(); i++)
128     {
129         RendererD3D *renderer = rendererCreationFunctions[i](display);
130         egl::Error result     = renderer->initialize();
131 
132 #if defined(ANGLE_ENABLE_D3D11)
133         if (renderer->getRendererClass() == RENDERER_D3D11)
134         {
135             ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS);
136             ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11InitializeResult", result.getID(),
137                                         NUM_D3D11_INIT_ERRORS);
138         }
139 #endif
140 
141 #if defined(ANGLE_ENABLE_D3D9)
142         if (renderer->getRendererClass() == RENDERER_D3D9)
143         {
144             ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS);
145             ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D9InitializeResult", result.getID(),
146                                         NUM_D3D9_INIT_ERRORS);
147         }
148 #endif
149 
150         if (!result.isError())
151         {
152             *outRenderer = renderer;
153             return result;
154         }
155 
156         // Failed to create the renderer, try the next
157         SafeDelete(renderer);
158         ERR() << "Failed to create D3D renderer: " << result.getMessage();
159     }
160 
161     return egl::EglNotInitialized() << "No available renderers.";
162 }
163 
DisplayD3D(const egl::DisplayState & state)164 DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr) {}
165 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)166 SurfaceImpl *DisplayD3D::createWindowSurface(const egl::SurfaceState &state,
167                                              EGLNativeWindowType window,
168                                              const egl::AttributeMap &attribs)
169 {
170     ASSERT(mRenderer != nullptr);
171     return new WindowSurfaceD3D(state, mRenderer, mDisplay, window, attribs);
172 }
173 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)174 SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::SurfaceState &state,
175                                               const egl::AttributeMap &attribs)
176 {
177     ASSERT(mRenderer != nullptr);
178     return new PbufferSurfaceD3D(state, mRenderer, mDisplay, 0, nullptr, attribs);
179 }
180 
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)181 SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::SurfaceState &state,
182                                                        EGLenum buftype,
183                                                        EGLClientBuffer clientBuffer,
184                                                        const egl::AttributeMap &attribs)
185 {
186     ASSERT(mRenderer != nullptr);
187     return new PbufferSurfaceD3D(state, mRenderer, mDisplay, buftype, clientBuffer, attribs);
188 }
189 
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)190 SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::SurfaceState &state,
191                                              NativePixmapType nativePixmap,
192                                              const egl::AttributeMap &attribs)
193 {
194     UNIMPLEMENTED();
195     return nullptr;
196 }
197 
createImage(const egl::ImageState & state,const gl::Context * context,EGLenum target,const egl::AttributeMap & attribs)198 ImageImpl *DisplayD3D::createImage(const egl::ImageState &state,
199                                    const gl::Context *context,
200                                    EGLenum target,
201                                    const egl::AttributeMap &attribs)
202 {
203     return new EGLImageD3D(state, target, attribs, mRenderer);
204 }
205 
createDevice()206 DeviceImpl *DisplayD3D::createDevice()
207 {
208     return mRenderer->createEGLDevice();
209 }
210 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)211 rx::ContextImpl *DisplayD3D::createContext(const gl::State &state,
212                                            gl::ErrorSet *errorSet,
213                                            const egl::Config *configuration,
214                                            const gl::Context *shareContext,
215                                            const egl::AttributeMap &attribs)
216 {
217     ASSERT(mRenderer != nullptr);
218     return mRenderer->createContext(state, errorSet);
219 }
220 
createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType,const egl::AttributeMap & attribs)221 StreamProducerImpl *DisplayD3D::createStreamProducerD3DTexture(
222     egl::Stream::ConsumerType consumerType,
223     const egl::AttributeMap &attribs)
224 {
225     ASSERT(mRenderer != nullptr);
226     return mRenderer->createStreamProducerD3DTexture(consumerType, attribs);
227 }
228 
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)229 ExternalImageSiblingImpl *DisplayD3D::createExternalImageSibling(const gl::Context *context,
230                                                                  EGLenum target,
231                                                                  EGLClientBuffer buffer,
232                                                                  const egl::AttributeMap &attribs)
233 {
234     ASSERT(mRenderer != nullptr);
235     return mRenderer->createExternalImageSibling(context, target, buffer, attribs);
236 }
237 
createShareGroup()238 ShareGroupImpl *DisplayD3D::createShareGroup()
239 {
240     return new ShareGroupD3D();
241 }
242 
makeCurrent(egl::Display * display,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)243 egl::Error DisplayD3D::makeCurrent(egl::Display *display,
244                                    egl::Surface *drawSurface,
245                                    egl::Surface *readSurface,
246                                    gl::Context *context)
247 {
248     // Ensure the appropriate global DebugAnnotator is used
249     ASSERT(mRenderer != nullptr);
250     mRenderer->setGlobalDebugAnnotator();
251 
252     return egl::NoError();
253 }
254 
initialize(egl::Display * display)255 egl::Error DisplayD3D::initialize(egl::Display *display)
256 {
257     ASSERT(mRenderer == nullptr && display != nullptr);
258     mDisplay = display;
259     ANGLE_TRY(CreateRendererD3D(display, &mRenderer));
260     return egl::NoError();
261 }
262 
terminate()263 void DisplayD3D::terminate()
264 {
265     SafeDelete(mRenderer);
266 }
267 
generateConfigs()268 egl::ConfigSet DisplayD3D::generateConfigs()
269 {
270     ASSERT(mRenderer != nullptr);
271     return mRenderer->generateConfigs();
272 }
273 
testDeviceLost()274 bool DisplayD3D::testDeviceLost()
275 {
276     ASSERT(mRenderer != nullptr);
277     return mRenderer->testDeviceLost();
278 }
279 
restoreLostDevice(const egl::Display * display)280 egl::Error DisplayD3D::restoreLostDevice(const egl::Display *display)
281 {
282     // Release surface resources to make the Reset() succeed
283     for (egl::Surface *surface : mState.surfaceSet)
284     {
285         ASSERT(!surface->getBoundTexture());
286         SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
287         surfaceD3D->releaseSwapChain();
288     }
289 
290     if (!mRenderer->resetDevice())
291     {
292         return egl::EglBadAlloc();
293     }
294 
295     // Restore any surfaces that may have been lost
296     for (const egl::Surface *surface : mState.surfaceSet)
297     {
298         SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
299 
300         ANGLE_TRY(surfaceD3D->resetSwapChain(display));
301     }
302 
303     return egl::NoError();
304 }
305 
isValidNativeWindow(EGLNativeWindowType window) const306 bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const
307 {
308     return mRenderer->isValidNativeWindow(window);
309 }
310 
validateClientBuffer(const egl::Config * config,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const311 egl::Error DisplayD3D::validateClientBuffer(const egl::Config *config,
312                                             EGLenum buftype,
313                                             EGLClientBuffer clientBuffer,
314                                             const egl::AttributeMap &attribs) const
315 {
316     switch (buftype)
317     {
318         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
319             return mRenderer->validateShareHandle(config, static_cast<HANDLE>(clientBuffer),
320                                                   attribs);
321 
322         case EGL_D3D_TEXTURE_ANGLE:
323             return mRenderer->getD3DTextureInfo(config, static_cast<IUnknown *>(clientBuffer),
324                                                 attribs, nullptr, nullptr, nullptr, nullptr,
325                                                 nullptr);
326 
327         default:
328             return DisplayImpl::validateClientBuffer(config, buftype, clientBuffer, attribs);
329     }
330 }
331 
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const332 egl::Error DisplayD3D::validateImageClientBuffer(const gl::Context *context,
333                                                  EGLenum target,
334                                                  EGLClientBuffer clientBuffer,
335                                                  const egl::AttributeMap &attribs) const
336 {
337     switch (target)
338     {
339         case EGL_D3D11_TEXTURE_ANGLE:
340         {
341             return mRenderer->getD3DTextureInfo(nullptr, static_cast<IUnknown *>(clientBuffer),
342                                                 attribs, nullptr, nullptr, nullptr, nullptr,
343                                                 nullptr);
344         }
345 
346         default:
347             return DisplayImpl::validateImageClientBuffer(context, target, clientBuffer, attribs);
348     }
349 }
350 
generateExtensions(egl::DisplayExtensions * outExtensions) const351 void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const
352 {
353     mRenderer->generateDisplayExtensions(outExtensions);
354 }
355 
getVendorString() const356 std::string DisplayD3D::getVendorString() const
357 {
358     std::string vendorString = "Google Inc.";
359     if (mRenderer)
360     {
361         vendorString += " " + mRenderer->getVendorString();
362     }
363 
364     return vendorString;
365 }
366 
generateCaps(egl::Caps * outCaps) const367 void DisplayD3D::generateCaps(egl::Caps *outCaps) const
368 {
369     // Display must be initialized to generate caps
370     ASSERT(mRenderer != nullptr);
371 
372     outCaps->textureNPOT = mRenderer->getNativeExtensions().textureNPOTOES;
373 }
374 
waitClient(const gl::Context * context)375 egl::Error DisplayD3D::waitClient(const gl::Context *context)
376 {
377     for (egl::Surface *surface : mState.surfaceSet)
378     {
379         SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
380         ANGLE_TRY(surfaceD3D->checkForOutOfDateSwapChain(this));
381     }
382 
383     return egl::NoError();
384 }
385 
waitNative(const gl::Context * context,EGLint engine)386 egl::Error DisplayD3D::waitNative(const gl::Context *context, EGLint engine)
387 {
388     egl::Surface *drawSurface = context->getCurrentDrawSurface();
389     egl::Surface *readSurface = context->getCurrentReadSurface();
390 
391     if (drawSurface != nullptr)
392     {
393         SurfaceD3D *drawSurfaceD3D = GetImplAs<SurfaceD3D>(drawSurface);
394         ANGLE_TRY(drawSurfaceD3D->checkForOutOfDateSwapChain(this));
395     }
396 
397     if (readSurface != nullptr)
398     {
399         SurfaceD3D *readSurfaceD3D = GetImplAs<SurfaceD3D>(readSurface);
400         ANGLE_TRY(readSurfaceD3D->checkForOutOfDateSwapChain(this));
401     }
402 
403     return egl::NoError();
404 }
405 
getMaxSupportedESVersion() const406 gl::Version DisplayD3D::getMaxSupportedESVersion() const
407 {
408     return mRenderer->getMaxSupportedESVersion();
409 }
410 
getMaxConformantESVersion() const411 gl::Version DisplayD3D::getMaxConformantESVersion() const
412 {
413     return mRenderer->getMaxConformantESVersion();
414 }
415 
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)416 void DisplayD3D::handleResult(HRESULT hr,
417                               const char *message,
418                               const char *file,
419                               const char *function,
420                               unsigned int line)
421 {
422     ASSERT(FAILED(hr));
423 
424     std::stringstream errorStream;
425     errorStream << "Internal D3D11 error: " << gl::FmtHR(hr) << ", in " << file << ", " << function
426                 << ":" << line << ". " << message;
427 
428     mStoredErrorString = errorStream.str();
429 }
430 
populateFeatureList(angle::FeatureList * features)431 void DisplayD3D::populateFeatureList(angle::FeatureList *features)
432 {
433     mRenderer->getFeatures().populateFeatureList(features);
434 }
435 
436 }  // namespace rx
437