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