1 //
2 // Copyright (c) 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_ENABLE_D3D9)
26 #   include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
27 #endif // ANGLE_ENABLE_D3D9
28 
29 #if defined (ANGLE_ENABLE_D3D11)
30 #   include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
31 #endif // ANGLE_ENABLE_D3D11
32 
33 #if !defined(ANGLE_DEFAULT_D3D11)
34 // Enables use of the Direct3D 11 API for a default display, when available
35 #   define ANGLE_DEFAULT_D3D11 1
36 #endif
37 
38 namespace rx
39 {
40 
41 typedef RendererD3D *(*CreateRendererD3DFunction)(egl::Display*);
42 
43 template <typename RendererType>
CreateTypedRendererD3D(egl::Display * display)44 static RendererD3D *CreateTypedRendererD3D(egl::Display *display)
45 {
46     return new RendererType(display);
47 }
48 
CreateRendererD3D(egl::Display * display,RendererD3D ** outRenderer)49 egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
50 {
51     ASSERT(outRenderer != nullptr);
52 
53     std::vector<CreateRendererD3DFunction> rendererCreationFunctions;
54 
55     if (display->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
56     {
57         const auto &attribMap              = display->getAttributeMap();
58         EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
59 
60         EGLint requestedDisplayType = static_cast<EGLint>(
61             attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
62 
63 #   if defined(ANGLE_ENABLE_D3D11)
64         if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
65             nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE ||
66             requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
67         {
68             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
69         }
70 #   endif
71 
72 #   if defined(ANGLE_ENABLE_D3D9)
73         if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
74             requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE)
75         {
76             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
77         }
78 #   endif
79 
80         if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
81             nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
82             requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
83         {
84         // The default display is requested, try the D3D9 and D3D11 renderers, order them using
85         // the definition of ANGLE_DEFAULT_D3D11
86 #       if ANGLE_DEFAULT_D3D11
87 #           if defined(ANGLE_ENABLE_D3D11)
88             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
89 #           endif
90 #           if defined(ANGLE_ENABLE_D3D9)
91             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
92 #           endif
93 #       else
94 #           if defined(ANGLE_ENABLE_D3D9)
95             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
96 #           endif
97 #           if defined(ANGLE_ENABLE_D3D11)
98             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
99 #           endif
100 #       endif
101         }
102     }
103     else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
104     {
105 #if defined(ANGLE_ENABLE_D3D11)
106         if (display->getDevice()->getType() == EGL_D3D11_DEVICE_ANGLE)
107         {
108             rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
109         }
110 #endif
111     }
112     else
113     {
114         UNIMPLEMENTED();
115     }
116 
117     for (size_t i = 0; i < rendererCreationFunctions.size(); i++)
118     {
119         RendererD3D *renderer = rendererCreationFunctions[i](display);
120         egl::Error result     = renderer->initialize();
121 
122 #       if defined(ANGLE_ENABLE_D3D11)
123             if (renderer->getRendererClass() == RENDERER_D3D11)
124             {
125                 ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS);
126                 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11InitializeResult",
127                                             result.getID(),
128                                             NUM_D3D11_INIT_ERRORS);
129             }
130 #       endif
131 
132 #       if defined(ANGLE_ENABLE_D3D9)
133             if (renderer->getRendererClass() == RENDERER_D3D9)
134             {
135                 ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS);
136                 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D9InitializeResult",
137                                             result.getID(),
138                                             NUM_D3D9_INIT_ERRORS);
139             }
140 #       endif
141 
142         if (!result.isError())
143         {
144             *outRenderer = renderer;
145             return result;
146         }
147 
148         // Failed to create the renderer, try the next
149         SafeDelete(renderer);
150     }
151 
152     return egl::EglNotInitialized() << "No available renderers.";
153 }
154 
DisplayD3D(const egl::DisplayState & state)155 DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr)
156 {
157 }
158 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)159 SurfaceImpl *DisplayD3D::createWindowSurface(const egl::SurfaceState &state,
160                                              EGLNativeWindowType window,
161                                              const egl::AttributeMap &attribs)
162 {
163     ASSERT(mRenderer != nullptr);
164     return new WindowSurfaceD3D(state, mRenderer, mDisplay, window, attribs);
165 }
166 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)167 SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::SurfaceState &state,
168                                               const egl::AttributeMap &attribs)
169 {
170     ASSERT(mRenderer != nullptr);
171     return new PbufferSurfaceD3D(state, mRenderer, mDisplay, 0, nullptr, attribs);
172 }
173 
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)174 SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::SurfaceState &state,
175                                                        EGLenum buftype,
176                                                        EGLClientBuffer clientBuffer,
177                                                        const egl::AttributeMap &attribs)
178 {
179     ASSERT(mRenderer != nullptr);
180     return new PbufferSurfaceD3D(state, mRenderer, mDisplay, buftype, clientBuffer, attribs);
181 }
182 
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)183 SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::SurfaceState &state,
184                                              NativePixmapType nativePixmap,
185                                              const egl::AttributeMap &attribs)
186 {
187     UNIMPLEMENTED();
188     return nullptr;
189 }
190 
createImage(const egl::ImageState & state,EGLenum target,const egl::AttributeMap & attribs)191 ImageImpl *DisplayD3D::createImage(const egl::ImageState &state,
192                                    EGLenum target,
193                                    const egl::AttributeMap &attribs)
194 {
195     return new EGLImageD3D(state, target, attribs, mRenderer);
196 }
197 
getDevice(DeviceImpl ** device)198 egl::Error DisplayD3D::getDevice(DeviceImpl **device)
199 {
200     return mRenderer->getEGLDevice(device);
201 }
202 
createContext(const gl::ContextState & state)203 ContextImpl *DisplayD3D::createContext(const gl::ContextState &state)
204 {
205     ASSERT(mRenderer != nullptr);
206     return mRenderer->createContext(state);
207 }
208 
createStreamProducerD3DTextureNV12(egl::Stream::ConsumerType consumerType,const egl::AttributeMap & attribs)209 StreamProducerImpl *DisplayD3D::createStreamProducerD3DTextureNV12(
210     egl::Stream::ConsumerType consumerType,
211     const egl::AttributeMap &attribs)
212 {
213     ASSERT(mRenderer != nullptr);
214     return mRenderer->createStreamProducerD3DTextureNV12(consumerType, attribs);
215 }
216 
makeCurrent(egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)217 egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context)
218 {
219     return egl::NoError();
220 }
221 
initialize(egl::Display * display)222 egl::Error DisplayD3D::initialize(egl::Display *display)
223 {
224     ASSERT(mRenderer == nullptr && display != nullptr);
225     mDisplay = display;
226     ANGLE_TRY(CreateRendererD3D(display, &mRenderer));
227     return egl::NoError();
228 }
229 
terminate()230 void DisplayD3D::terminate()
231 {
232     SafeDelete(mRenderer);
233 }
234 
generateConfigs()235 egl::ConfigSet DisplayD3D::generateConfigs()
236 {
237     ASSERT(mRenderer != nullptr);
238     return mRenderer->generateConfigs();
239 }
240 
testDeviceLost()241 bool DisplayD3D::testDeviceLost()
242 {
243     ASSERT(mRenderer != nullptr);
244     return mRenderer->testDeviceLost();
245 }
246 
restoreLostDevice(const egl::Display * display)247 egl::Error DisplayD3D::restoreLostDevice(const egl::Display *display)
248 {
249     // Release surface resources to make the Reset() succeed
250     for (egl::Surface *surface : mState.surfaceSet)
251     {
252         if (surface->getBoundTexture())
253         {
254             ANGLE_TRY(surface->releaseTexImage(display->getProxyContext(), EGL_BACK_BUFFER));
255         }
256         SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
257         surfaceD3D->releaseSwapChain();
258     }
259 
260     if (!mRenderer->resetDevice())
261     {
262         return egl::EglBadAlloc();
263     }
264 
265     // Restore any surfaces that may have been lost
266     for (const egl::Surface *surface : mState.surfaceSet)
267     {
268         SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
269 
270         ANGLE_TRY(surfaceD3D->resetSwapChain(display));
271     }
272 
273     return egl::NoError();
274 }
275 
isValidNativeWindow(EGLNativeWindowType window) const276 bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const
277 {
278     return mRenderer->isValidNativeWindow(window);
279 }
280 
validateClientBuffer(const egl::Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const281 egl::Error DisplayD3D::validateClientBuffer(const egl::Config *configuration,
282                                             EGLenum buftype,
283                                             EGLClientBuffer clientBuffer,
284                                             const egl::AttributeMap &attribs) const
285 {
286     switch (buftype)
287     {
288         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
289             return mRenderer->validateShareHandle(configuration, static_cast<HANDLE>(clientBuffer),
290                                                   attribs);
291 
292         case EGL_D3D_TEXTURE_ANGLE:
293             return mRenderer->getD3DTextureInfo(
294                 configuration, static_cast<IUnknown *>(clientBuffer), nullptr, nullptr, nullptr);
295 
296         default:
297             return DisplayImpl::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
298     }
299 }
300 
generateExtensions(egl::DisplayExtensions * outExtensions) const301 void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const
302 {
303     mRenderer->generateDisplayExtensions(outExtensions);
304 }
305 
getVendorString() const306 std::string DisplayD3D::getVendorString() const
307 {
308     std::string vendorString = "Google Inc.";
309     if (mRenderer)
310     {
311         vendorString += " " + mRenderer->getVendorString();
312     }
313 
314     return vendorString;
315 }
316 
generateCaps(egl::Caps * outCaps) const317 void DisplayD3D::generateCaps(egl::Caps *outCaps) const
318 {
319     // Display must be initialized to generate caps
320     ASSERT(mRenderer != nullptr);
321 
322     outCaps->textureNPOT = mRenderer->getNativeExtensions().textureNPOT;
323 }
324 
waitClient(const gl::Context * context) const325 egl::Error DisplayD3D::waitClient(const gl::Context *context) const
326 {
327     for (egl::Surface *surface : mState.surfaceSet)
328     {
329         SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
330         ANGLE_TRY(surfaceD3D->checkForOutOfDateSwapChain(context));
331     }
332 
333     return egl::NoError();
334 }
335 
waitNative(const gl::Context * context,EGLint engine) const336 egl::Error DisplayD3D::waitNative(const gl::Context *context, EGLint engine) const
337 {
338     egl::Surface *drawSurface = context->getCurrentDrawSurface();
339     egl::Surface *readSurface = context->getCurrentReadSurface();
340 
341     if (drawSurface != nullptr)
342     {
343         SurfaceD3D *drawSurfaceD3D = GetImplAs<SurfaceD3D>(drawSurface);
344         ANGLE_TRY(drawSurfaceD3D->checkForOutOfDateSwapChain(context));
345     }
346 
347     if (readSurface != nullptr)
348     {
349         SurfaceD3D *readSurfaceD3D = GetImplAs<SurfaceD3D>(readSurface);
350         ANGLE_TRY(readSurfaceD3D->checkForOutOfDateSwapChain(context));
351     }
352 
353     return egl::NoError();
354 }
355 
getMaxSupportedESVersion() const356 gl::Version DisplayD3D::getMaxSupportedESVersion() const
357 {
358     return mRenderer->getMaxSupportedESVersion();
359 }
360 
361 }  // namespace rx
362