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