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