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