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